diff --git a/lib/syskit/network_generation/engine.rb b/lib/syskit/network_generation/engine.rb index 1759364cd..807d6640d 100644 --- a/lib/syskit/network_generation/engine.rb +++ b/lib/syskit/network_generation/engine.rb @@ -89,7 +89,6 @@ def initialize( event_logger: event_logger, resolution_control: resolution_control ) - @used_deployments = {} @required_instances = {} end @@ -128,13 +127,12 @@ def compute_deployed_network( resolution_control: @resolution_control ) - used_deployments, = deployer.deploy( + deployer.deploy( error_handler: error_handler, validate: validate_deployed_network, lazy: lazy_deploy ) - @used_deployments = @used_deployments.merge(used_deployments) - resolution_errors = error_handler.process_failures( - required_instances, cleanup_failed_tasks: true + resolution_errors = process_failures( + error_handler, required_instances, cleanup_failed_tasks: true ) # Sanity check that the plan was properly cleaned up SystemNetworkDeployer.verify_all_tasks_deployed( @@ -174,7 +172,7 @@ def apply_deployed_network_to_plan @deployment_tasks, @deployed_tasks = log_timepoint_group "finalize_deployed_tasks" do adaptation = RuntimeNetworkAdaptation.new( - work_plan, @used_deployments, + work_plan, merge_solver: @merge_solver, event_logger: @event_logger, resolution_control: @resolution_control @@ -394,7 +392,7 @@ def compute_system_network( instance_requirements ) - _, @used_deployments = system_network_generator.resolve_system_network( + system_network_generator.resolve_system_network( garbage_collect: garbage_collect, validate_abstract_network: validate_abstract_network, validate_generated_network: validate_generated_network, @@ -406,7 +404,8 @@ def compute_system_network( toplevel_tasks_to_requirements = system_network_generator.toplevel_tasks_to_requirements - resolution_errors = error_handler.process_failures( + resolution_errors = process_failures( + error_handler, required_instances, cleanup_failed_tasks: cleanup_resolution_errors ) @@ -423,6 +422,16 @@ def compute_system_network( [required_instances, resolution_errors, toplevel_tasks_to_requirements] end + def process_failures(error_handler, required_instances, cleanup_failed_tasks:) + resolution_errors = error_handler.process_failures(required_instances) + return resolution_errors unless cleanup_failed_tasks + + error_handler.cleanup_resolution_errors( + resolution_errors, required_instances, work_plan + ) + resolution_errors + end + # Computes the system network, that is the network that fullfills # a list of requirements # diff --git a/lib/syskit/network_generation/resolution_error_handler.rb b/lib/syskit/network_generation/resolution_error_handler.rb index 7937d135f..842de736a 100644 --- a/lib/syskit/network_generation/resolution_error_handler.rb +++ b/lib/syskit/network_generation/resolution_error_handler.rb @@ -151,11 +151,11 @@ def failures_from_exception(tasks, plan, merge_solver, exception) end end - def process_failures(required_instances, cleanup_failed_tasks:) + def process_failures(required_instances) requirement_tasks = required_instances.keys toplevel_tasks = required_instances.values - resolution_errors = @resolution_failures.flat_map do |failure| + @resolution_failures.flat_map do |failure| failed_task = failure.failed_task indexes = find_index_of_toplevel_tasks_depending_on( failed_task, toplevel_tasks, failure.plan, failure.merge_solver @@ -165,14 +165,6 @@ def process_failures(required_instances, cleanup_failed_tasks:) failure.to_resolution_errors(instance) end end - - if cleanup_failed_tasks - cleanup_resolution_errors( - resolution_errors, required_instances, @plan - ) - end - - resolution_errors end # Cleanup the requirement tasks and toplevel tasks that encountered resolution @@ -188,19 +180,24 @@ def cleanup_resolution_errors( requirement_task = error.planning_task required_instances.delete requirement_task end - return if resolution_errors.empty? + return [] if resolution_errors.empty? NetworkGeneration.debug "cleanup up after error resolution" protected_tasks = required_instances.values.map do |v| @merge_solver.replacement_for(v) end + + removed_tasks = [] work_plan .static_garbage_collect(protected_roots: protected_tasks) do |obj| NetworkGeneration.debug { " removing #{obj}" } # Remove tasks that are not useful anymore @plan.remove_task(obj) + removed_tasks << obj end @resolution_failures.clear + + removed_tasks end end @@ -215,6 +212,8 @@ def register_resolution_failures_from_exception(_tasks, exception) def process_failures(*) [] end + + def cleanup_resolution_errors(*); end end end end diff --git a/lib/syskit/network_generation/runtime_network_adaptation.rb b/lib/syskit/network_generation/runtime_network_adaptation.rb index f90c4aaa0..e86d93cbc 100644 --- a/lib/syskit/network_generation/runtime_network_adaptation.rb +++ b/lib/syskit/network_generation/runtime_network_adaptation.rb @@ -14,7 +14,7 @@ class RuntimeNetworkAdaptation # @param [{Component=>DeploymentGroup::DeployedTask}] used_deployments the # mapping from task instances to the deployment used for it def initialize( - work_plan, used_deployments, + work_plan, merge_solver:, event_logger: work_plan.event_logger, resolution_control: Async::Control.new @@ -24,6 +24,7 @@ def initialize( @resolution_control = resolution_control @merge_solver = merge_solver + used_deployments = find_used_deployments(work_plan) tasks_per_configured_deployments = used_deployments.each_with_object({}) do |(task, deployed_task), h| (h[deployed_task.configured_deployment] ||= []) << task @@ -36,6 +37,12 @@ def initialize( end end + def find_used_deployments(work_plan) + work_plan.find_local_tasks(TaskContext).each_with_object({}) do |t, h| + h[t] = t.deployed_task + end + end + def apply result = finalize_deployed_tasks sever_old_plan_from_new_plan diff --git a/lib/syskit/network_generation/system_network_deployer.rb b/lib/syskit/network_generation/system_network_deployer.rb index bef3b005c..2ccffa8dd 100644 --- a/lib/syskit/network_generation/system_network_deployer.rb +++ b/lib/syskit/network_generation/system_network_deployer.rb @@ -236,6 +236,7 @@ def apply_selected_deployments(selected_deployments, deployment_tasks = {}) # subnet. This is not the goal here. merge_solver.apply_merge_group(task => deployed_task) used_deployments[deployed_task] = deployed_task_m + deployed_task.deployed_task = deployed_task_m used_deployments.merge!( apply_selected_deployments_discover_schedulers( @@ -261,6 +262,7 @@ def apply_selected_deployments_discover_schedulers( recursive = apply_selected_deployments_discover_schedulers( scheduler_task, configured_deployment ) + scheduler_task.deployed_task = scheduler_deployed_task { scheduler_task => scheduler_deployed_task }.merge(recursive) end @@ -279,6 +281,10 @@ def lazy_apply_selected_deployments(selected_deployments) task.orogen_model = sel.orogen_model task.orogen_model.master end + selected_deployments.each do |task, sel| + task.deployed_task = sel + end + return selected_deployments if with_master.empty? used_deployments = selected_deployments.dup @@ -294,6 +300,7 @@ def lazy_apply_selected_deployments(selected_deployments) scheduler_deployed_task = Models::DeploymentGroup::DeployedTask.new( deployment, scheduler_name ) + scheduler_task.deployed_task = task.deployed_task used_deployments[scheduler_task] = scheduler_deployed_task end used_deployments diff --git a/lib/syskit/network_generation/system_network_generator.rb b/lib/syskit/network_generation/system_network_generator.rb index 206ebef72..bd23247d9 100644 --- a/lib/syskit/network_generation/system_network_generator.rb +++ b/lib/syskit/network_generation/system_network_generator.rb @@ -268,7 +268,6 @@ def resolve_system_network( validate_deployed_network: true ) deployment_tasks = {} - @used_deployments = {} early_deploy(deployment_tasks) merge_solver.merge_identical_tasks @@ -324,15 +323,13 @@ def resolve_system_network( ) interruption_point("syskit-netgen:validation") - @used_deployments.transform_keys! { @merge_solver.replacement_for(_1) } - [@toplevel_tasks, @used_deployments] + @toplevel_tasks end def early_deploy(deployment_tasks) return unless early_deploy? - used_deployments, = deploy(deployment_tasks) - @used_deployments.merge!(used_deployments) + deploy(deployment_tasks) interruption_point "syskit-netgen:early-deploy" end diff --git a/lib/syskit/task_context.rb b/lib/syskit/task_context.rb index 989a582e4..3fa2bbbb5 100644 --- a/lib/syskit/task_context.rb +++ b/lib/syskit/task_context.rb @@ -59,6 +59,8 @@ class TaskContext < Component # The last state before we went to orogen_state attr_reader :last_orogen_state + attr_accessor :deployed_task + # @api private # # Initialize the communication with the remote task @@ -326,6 +328,10 @@ def merge(merged_task) if merged_task.orocos_task && !orocos_task self.orocos_task = merged_task.orocos_task end + + if merged_task.deployed_task && !deployed_task + self.deployed_task = merged_task.deployed_task + end nil end diff --git a/test/network_generation/test_engine.rb b/test/network_generation/test_engine.rb index 45cad030c..458d6c7a8 100644 --- a/test/network_generation/test_engine.rb +++ b/test/network_generation/test_engine.rb @@ -529,7 +529,7 @@ def deploy_dev_and_bus assert_master_slave_pattern_correct end - it "deploys slave tasks when the deploymentc exists" do + it "deploys slave tasks when the deployment exists" do deployment_task = @configured_deployment.new(plan: plan) syskit_deploy( @@ -693,6 +693,62 @@ def assert_master_slave_pattern_correct(deployment_task: nil) assert_equal [t2.planning_task], required_instances.keys end end + + describe "#resolve" do + it "handles deployment errors during final deployment resolution " \ + "gracefully" do + task2_m = Syskit::TaskContext.new_submodel + task2_m.provides @srv_m, as: "srv" + + t1 = @cmp_m.use("test" => @task_m.new(arg: 2), + "other" => task2_m.new).as_plan + plan.add(t1) + + errors = syskit_engine.resolve( + requirement_tasks: [t1.planning_task], + capture_errors_during_network_resolution: true, + default_deployment_group: default_deployment_group, + cleanup_resolution_errors: true + ) + assert_equal 1, errors.size + assert_kind_of MissingDeployment, + errors.first.original_exception + end + + it "handles deployment errors during network adaption with bad new " \ + "task" do + t1 = @task_m.with_arguments(arg: 1).as_plan + plan.add(t1) + + t1 = t1.as_service + syskit_engine.resolve( + requirement_tasks: [t1.planning_task], + default_deployment_group: default_deployment_group, + capture_errors_during_network_resolution: true, + early_deploy: true, + cleanup_resolution_errors: true + ) + + new_engine = Syskit::NetworkGeneration::Engine.new(plan) + t2 = @task_m.with_arguments(arg: 2).as_plan + plan.add(t2) + + errors = new_engine.resolve( + requirement_tasks: [t1.planning_task, t2.planning_task], + default_deployment_group: default_deployment_group, + capture_errors_during_network_resolution: true, + early_deploy: true, + cleanup_resolution_errors: true + ) + # Both of the tasks will emit a ConflictingDeploymentAllocation + # with one another + assert_equal 2, errors.size + errors.each do |e| + assert_kind_of ConflictingDeploymentAllocation, + e.original_exception + end + end + end end describe "when scheduling tasks for reconfiguration" do diff --git a/test/network_generation/test_runtime_network_adaptation.rb b/test/network_generation/test_runtime_network_adaptation.rb index 9f357f4db..0091432bb 100644 --- a/test/network_generation/test_runtime_network_adaptation.rb +++ b/test/network_generation/test_runtime_network_adaptation.rb @@ -22,9 +22,8 @@ module NetworkGeneration deployment_m = create_deployment_model(task_count: 1) _, initial = add_deployment_and_tasks(work_plan, deployment_m, %w[task0]) - adapter = create_adapter( - used_deployments_from_tasks(initial) - ) + register_deployments_for_tasks(initial) + adapter = create_adapter existing_deployment, = add_deployment_and_tasks(plan, deployment_m, %w[task0]) @@ -39,7 +38,7 @@ module NetworkGeneration deployment_m = create_deployment_model(task_count: 1) add_deployment_and_tasks(plan, deployment_m, %w[task0]) - adapter = create_adapter({}) + adapter = create_adapter selected_deployments, = adapter.finalize_deployed_tasks assert selected_deployments.empty? end @@ -49,9 +48,8 @@ module NetworkGeneration required_deployment, tasks = add_deployment_and_tasks(work_plan, deployment, %w[task0 task1]) - adapter = create_adapter( - used_deployments_from_tasks(tasks) - ) + register_deployments_for_tasks(tasks) + adapter = create_adapter selected_deployments, selected_deployed_tasks = adapter.finalize_deployed_tasks @@ -74,9 +72,11 @@ module NetworkGeneration # automatically create the scheduler too required_deployment, = add_deployment_and_tasks(work_plan, deployment, %w[scheduled]) - adapter = create_adapter( - used_deployments_from_tasks(plan.find_tasks(task_m).to_a) - ) + + tasks = required_deployment.related_tasks + register_deployments_for_tasks(tasks) + adapter = create_adapter + adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -100,9 +100,8 @@ module NetworkGeneration work_plan, deployment_m, %w[task0 task2] ) - adapter = create_adapter( - used_deployments_from_tasks([required0, task2]) - ) + register_deployments_for_tasks([required0, task2]) + adapter = create_adapter selected_deployments, selected_deployed_tasks = adapter.finalize_deployed_tasks @@ -133,9 +132,9 @@ module NetworkGeneration existing0.depends_on(existing1) - adapter = create_adapter( - used_deployments_from_tasks([required0, required1]) - ) + register_deployments_for_tasks([required0, required1]) + adapter = create_adapter + adapter.finalize_deployed_tasks assert work_plan[existing0].depends_on?(work_plan[existing1]) @@ -153,9 +152,10 @@ module NetworkGeneration required0.depends_on required2 required1.depends_on required2 - adapter = create_adapter( - used_deployments_from_tasks([required0, required1, required2]) - ) + register_deployments_for_tasks([required0, required1, + required2]) + adapter = create_adapter + adapter.finalize_deployed_tasks required2 = work_plan[existing0].children.first @@ -171,7 +171,8 @@ module NetworkGeneration _, tasks = add_deployment_and_tasks(work_plan, deployment_m, %w[task0]) - adapter = create_adapter(used_deployments_from_tasks(tasks)) + register_deployments_for_tasks(tasks) + adapter = create_adapter assert_raises Syskit::InternalError do adapter.finalize_deployed_tasks end @@ -193,9 +194,9 @@ module NetworkGeneration add_deployment_and_tasks( work_plan, deployment_m, %w[scheduled1 scheduled2] ) - adapter = create_adapter( - used_deployments_from_tasks(work_plan.find_tasks(task_m).to_a) - ) + register_deployments_for_tasks(work_plan.find_tasks(task_m).to_a) + adapter = create_adapter + adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -227,9 +228,9 @@ module NetworkGeneration add_deployment_and_tasks( work_plan, deployment_m, %w[scheduled1 scheduled2] ) - adapter = create_adapter( - used_deployments_from_tasks(work_plan.find_tasks(task_m).to_a) - ) + register_deployments_for_tasks(work_plan.find_tasks(task_m).to_a) + adapter = create_adapter + adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -253,9 +254,8 @@ module NetworkGeneration existing_deployment, = add_deployment_and_tasks(plan, deployment_m, %w[task0]) initial = add_lazy_tasks(work_plan, deployment_m, %w[task0]) - adapter = create_adapter( - used_deployments_from_lazy(initial, deployment_m) - ) + lazy_register_deployments_for_tasks(initial, deployment_m) + adapter = create_adapter selected_deployments, = adapter.finalize_deployed_tasks assert_equal [work_plan[existing_deployment]], @@ -267,7 +267,7 @@ module NetworkGeneration deployment_m = create_deployment_model(task_count: 1) add_deployment_and_tasks(plan, deployment_m, %w[task0]) - adapter = create_adapter({}) + adapter = create_adapter selected_deployments, = adapter.finalize_deployed_tasks assert selected_deployments.empty? end @@ -275,9 +275,8 @@ module NetworkGeneration it "creates a new deployment if needed" do deployment_m = create_deployment_model(task_count: 2) tasks = add_lazy_tasks(work_plan, deployment_m, %w[task0 task1]) - adapter = create_adapter( - used_deployments_from_lazy(tasks, deployment_m) - ) + lazy_register_deployments_for_tasks(tasks, deployment_m) + adapter = create_adapter selected_deployments, = adapter.finalize_deployed_tasks @@ -298,9 +297,9 @@ module NetworkGeneration work_plan, deployment_m, %w[task0 task2] ) - adapter = create_adapter( - used_deployments_from_lazy([required0, task2], deployment_m) - ) + lazy_register_deployments_for_tasks([required0, task2], + deployment_m) + adapter = create_adapter selected_deployments, selected_deployed_tasks = adapter.finalize_deployed_tasks @@ -330,11 +329,11 @@ module NetworkGeneration existing0.depends_on(existing1) - adapter = create_adapter( - used_deployments_from_lazy( - [required0, required1], deployment_m - ) + lazy_register_deployments_for_tasks( + [required0, required1], deployment_m ) + adapter = create_adapter + adapter.finalize_deployed_tasks assert work_plan[existing0].depends_on?(work_plan[existing1]) @@ -351,11 +350,11 @@ module NetworkGeneration required0.depends_on required2 required1.depends_on required2 - adapter = create_adapter( - used_deployments_from_lazy( - [required0, required1, required2], deployment_m - ) + lazy_register_deployments_for_tasks( + [required0, required1, required2], deployment_m ) + adapter = create_adapter + adapter.finalize_deployed_tasks required2 = work_plan[existing0].children.first @@ -370,9 +369,9 @@ module NetworkGeneration add_deployment_and_tasks(plan, deployment_m, %w[task0]) tasks = add_lazy_tasks(work_plan, deployment_m, %w[task0]) - adapter = create_adapter( - used_deployments_from_lazy(tasks, deployment_m) - ) + lazy_register_deployments_for_tasks(tasks, deployment_m) + adapter = create_adapter + assert_raises Syskit::InternalError do adapter.finalize_deployed_tasks end @@ -393,9 +392,8 @@ module NetworkGeneration ) tasks[0].depends_on(tasks.last) tasks[1].depends_on(tasks.last) - adapter = create_adapter( - used_deployments_from_lazy(tasks, deployment_m) - ) + lazy_register_deployments_for_tasks(tasks, deployment_m) + adapter = create_adapter adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -428,9 +426,8 @@ module NetworkGeneration ) tasks[0].depends_on(tasks.last) tasks[1].depends_on(tasks.last) - adapter = create_adapter( - used_deployments_from_lazy(tasks, deployment_m) - ) + lazy_register_deployments_for_tasks(tasks, deployment_m) + adapter = create_adapter adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -464,9 +461,9 @@ module NetworkGeneration ) tasks[0].depends_on(tasks.last) tasks[1].depends_on(tasks.last) - adapter = create_adapter( - used_deployments_from_lazy(tasks, deployment_m) - ) + lazy_register_deployments_for_tasks(tasks, deployment_m) + adapter = create_adapter + adapter.finalize_deployed_tasks tasks = @work_plan.find_tasks(task_m).sort_by(&:orocos_name) @@ -512,7 +509,7 @@ def add_lazy_tasks(plan, deployment_m, task_names) describe "#reconfigure_tasks_on_static_port_modification" do before do @adapter = RuntimeNetworkAdaptation.new( - @work_plan, {}, merge_solver: @merge_solver + @work_plan, merge_solver: @merge_solver ) end @@ -588,7 +585,7 @@ def add_lazy_tasks(plan, deployment_m, task_names) .pass_thru work_plan.add(@deployment_task = EngineTestStubDeployment.new(task_m)) @adapter = RuntimeNetworkAdaptation.new( - @work_plan, {}, merge_solver: @merge_solver + @work_plan, merge_solver: @merge_solver ) end @@ -687,7 +684,7 @@ def add_lazy_tasks(plan, deployment_m, task_names) task1.should_configure_after(task0.stop_event) task0 = work_plan[task0] task1 = work_plan[task1] - adapter = create_adapter([]) + adapter = create_adapter assert_equal task1, adapter.find_current_deployed_task([task0, task1]) end @@ -700,7 +697,7 @@ def add_lazy_tasks(plan, deployment_m, task_names) execute { plan.garbage_task(task0) } task0 = work_plan[task0] task1 = work_plan[task1] - adapter = create_adapter([]) + adapter = create_adapter assert_equal task1, adapter.find_current_deployed_task([task0, task1]) end @@ -713,36 +710,35 @@ def add_lazy_tasks(plan, deployment_m, task_names) task1.do_not_reuse task0 = work_plan[task0] task1 = work_plan[task1] - adapter = create_adapter([]) + adapter = create_adapter assert_equal task1, adapter.find_current_deployed_task([task0, task1]) end end - def create_adapter(used_deployments) - RuntimeNetworkAdaptation.new(work_plan, used_deployments, - merge_solver: @merge_solver) + def create_adapter + RuntimeNetworkAdaptation.new(work_plan, merge_solver: @merge_solver) end - def used_deployments_from_tasks(tasks) + def register_deployments_for_tasks(tasks) configured_deployments = tasks.each_with_object({}) do |task, per_name| name = task.execution_agent.process_name per_name[name] ||= flexmock(process_name: name) end - tasks.each_with_object({}) do |task, used_deployments| + tasks.each do |task| name = task.execution_agent.process_name - used_deployments[task] = flexmock( + task.deployed_task = flexmock( configured_deployment: configured_deployments.fetch(name) ) end end - def used_deployments_from_lazy(tasks, deployment_m) + def lazy_register_deployments_for_tasks(tasks, deployment_m) configured_deployment = Models::ConfiguredDeployment.new( "localhost", deployment_m ) - tasks.each_with_object({}) do |task, used_deployments| - used_deployments[task] = + tasks.each_with_object({}) do |task, _used_deployments| + task.deployed_task = flexmock(configured_deployment: configured_deployment) end end diff --git a/test/network_generation/test_system_network_generator.rb b/test/network_generation/test_system_network_generator.rb index 6cddf157d..ae6f98e3e 100644 --- a/test/network_generation/test_system_network_generator.rb +++ b/test/network_generation/test_system_network_generator.rb @@ -236,7 +236,7 @@ def arg=(value) default_deployment_group: Models::DeploymentGroup.new, early_deploy: true, lazy_deploy: true ) - toplevel_tasks, = local_net_gen.compute_system_network( + toplevel_tasks = local_net_gen.compute_system_network( [task_m.to_instance_requirements .use_deployment(deployment_m)], validate_deployed_network: true @@ -444,6 +444,10 @@ def arg=(value) expected_message = <<~MSG deployed task 'task1' from deployment 'task1' defined in '' on 'stubs' is assigned to 2 tasks. Below is the list of the dependent non-deployed actions. Right after the list is a detailed explanation of why the first two tasks are not merged: + T(arg: 1, conf: ["default"], orocos_name: task1, read_only: false) is needed by the following definitions: + #.use( task => T .with_arguments( arg => 1 ) + T(arg: 2, conf: ["default"], orocos_name: task1, read_only: false) is needed by the following definitions: + #.use( task => T .with_arguments( arg => 2 ) Chain 1 cannot be merged in chain 2: Chain 1: T pending @@ -488,9 +492,7 @@ def resolve_system_network(requirement_tasks, garbage_collect: true) ) required_instances = Hash[requirement_tasks.zip(toplevel_tasks)] - errors = error_handler.process_failures( - required_instances, cleanup_failed_tasks: true - ) + errors = error_handler.process_failures(required_instances) [toplevel_tasks, errors] end end diff --git a/test/test_task_context.rb b/test/test_task_context.rb index 16ccf25d8..2a2b01b04 100644 --- a/test/test_task_context.rb +++ b/test/test_task_context.rb @@ -1497,12 +1497,23 @@ def setup_task(task = self.task, expected_messages: nil) emit dev_driver.start_event end end + bus_msgs = messages.find_all do |m| + m.include?("bus_task") || m.include?("BusDriver") + end + dev_msgs = messages.find_all do |m| + m.include?("dev_task") || + (m.include?("Driver") && !m.include?("BusDriver")) + end + assert_equal ["applied configuration [\"default\"] to #{bus_driver.orocos_name}", "setting up #{bus_driver}", - "starting #{bus_driver}", - "applied configuration [\"default\"] to #{dev_driver.orocos_name}", + "starting #{bus_driver}"], bus_msgs + assert_equal ["applied configuration [\"default\"] to #{dev_driver.orocos_name}", "setting up #{dev_driver}", - "starting #{dev_driver}"], messages + "starting #{dev_driver}"], dev_msgs + + assert_operator messages.index("starting #{bus_driver}"), :<, + messages.index("starting #{dev_driver}") end describe "transaction commit" do