Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/syskit/runtime/connection_management.rb
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,10 @@ def active_task?(t)

def update
# Don't do anything if the engine is deploying
return if plan.syskit_has_async_resolution?
if plan.syskit_has_async_resolution?
debug "connection: skipping, async resolution in progress"
return
end

tasks = dataflow_graph.modified_tasks
tasks.delete_if { |t| !active_task?(t) }
Expand Down
8 changes: 8 additions & 0 deletions lib/syskit/test/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def setup
@old_loglevel = Orocos.logger.level
@__syskit_test_updated_attrs = {}

@expect_execution_process_async_resolutions = true

super
end

Expand All @@ -42,6 +44,12 @@ def teardown
end
end

# Controls at the test level whether the execution expectation harness
# should poll async resolution results
#
# @see ExecutionExpectations#process_async_resolutions?
attr_accessor :expect_execution_process_async_resolutions

def __syskit_test_disable_taskcontext_info_messages
registered_plans.each do |p|
next unless p.executable?
Expand Down
38 changes: 38 additions & 0 deletions lib/syskit/test/execution_expectations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,44 @@ module Syskit
module Test
# Definition of expectations for Roby's expect_execution harness
module ExecutionExpectations
# Controls whether the execution expectation harness should explicitly
# process async resolutions and wait for them to finish
#
# The default is true
#
# @see #process_async_resolutions?
def process_async_resolutions(flag)
@process_async_resolutions = flag
self
end

# Controls whether the execution expectation harness should explicitly
# process async resolutions and wait for them to finish
#
# The default is true
#
# It can be controlled at the test level with
# {Base#expect_execution_process_async_resolutions=}
#
# @see #process_async_resolutions
def process_async_resolutions?
if @process_async_resolutions.nil?
@test.expect_execution_process_async_resolutions
else
@process_async_resolutions
end
end

Roby::Test::ExecutionExpectations.poll do |test, plan|
test.process_async_resolutions? &&
InstanceRequirementPlanningHandler
.process_async_resolution(test, plan)
end

Roby::Test::ExecutionExpectations.exit_allowed_condition do |test, plan|
!test.process_async_resolutions? || !plan.syskit_has_async_resolution?
end

# @api private
#
# Helper used to resolve reader objects
Expand Down
36 changes: 21 additions & 15 deletions lib/syskit/test/instance_requirement_planning_handler.rb
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refactor was indispensable or "just" an improvement on readability and responsibility?

Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ def apply_requirements
)
end

def replace_tasks_for_stub_network(results)
def self.replace_tasks_for_stub_network(test, plan, results)
root_tasks = results.instance_requirement_tasks.map(&:planned_task)
stub_network = StubNetwork.new(@test)
stub_network = StubNetwork.new(test)

# NOTE: this is a run-planner equivalent to syskit_stub_network
# we will have to investigate whether we could implement one with
# the other (probably), but in the meantime we must keep both
# in sync
mapped_tasks = @plan.in_transaction do |trsc|
mapped_tasks = plan.in_transaction do |trsc|
mapped_tasks =
stub_network.apply_in_transaction(trsc, root_tasks)
trsc.commit_transaction
Expand All @@ -80,24 +80,30 @@ def replace_tasks_for_stub_network(results)
# This is only relevant when we arent capturing errors during the network
# resolution. When we are capturing errors, the capture pipeline already deals
# with the failed task, and can deploy the stub network safely.
def consider_finished_due_to_errors?(results)
def self.consider_finished_due_to_errors?(results)
!Syskit.conf.capture_errors_during_network_resolution? && results.error?
end

def finished?
if @plan.syskit_has_async_resolution?
Thread.pass
def self.process_async_resolution(test, plan)
return unless plan.syskit_has_async_resolution?

async = @plan.syskit_current_resolution
@plan.syskit_poll_async_resolution(nil)
return if @plan.syskit_has_async_resolution?
Thread.pass

resolution_results = async.result
return true if consider_finished_due_to_errors?(resolution_results)
return unless @test.syskit_run_planner_stub?
async = plan.syskit_current_resolution
plan.syskit_poll_async_resolution(nil)
return if plan.syskit_has_async_resolution?

replace_tasks_for_stub_network(resolution_results)
end
resolution_results = async.result
return true if consider_finished_due_to_errors?(resolution_results)
return unless test.syskit_run_planner_stub?

replace_tasks_for_stub_network(
test, plan, resolution_results
)
end

def finished?
self.class.process_async_resolution(@test, @plan)

@planning_tasks.all? { |t| t.resolution_success? || t.finished? }
end
Expand Down
1 change: 1 addition & 0 deletions lib/syskit/test/spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def kill_running_async_resolution

plan.syskit_cancel_async_resolution
plan.syskit_join_current_resolution
plan.syskit_pending_forced_resolution = false
end

def teardown_registered_plans
Expand Down
1 change: 1 addition & 0 deletions test/network_generation/test_async_threaded.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module NetworkGeneration
describe AsyncThreaded do
before do
plan.syskit_async_method = AsyncThreaded
self.expect_execution_process_async_resolutions = false
end

describe "#poll" do
Expand Down
1 change: 1 addition & 0 deletions test/runtime/test_apply_requirement_modifications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module Runtime
before do
@__async_method = plan.syskit_async_method
plan.syskit_async_method = async_method
self.expect_execution_process_async_resolutions = false
end

after do
Expand Down
49 changes: 48 additions & 1 deletion test/test/test_execution_expectations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,61 @@ module Test
attr_reader :task

before do
task_m = Syskit::RubyTaskContext.new_submodel do
@task_m = task_m = Syskit::RubyTaskContext.new_submodel do
input_port "in", "/int"
output_port "out", "/int"
end
use_ruby_tasks task_m => "test", on: "stubs"
@task = syskit_deploy_configure_and_start(task_m)
end

describe "handling of apply_requirement_modifications" do
it "finishes within the test the resolutions " \
"created during the generation block" do
Comment on lines +21 to +22
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replicate the test for "finishes at the end"

plan.add(@task_m.as_plan)
expect_execution { Syskit::Runtime.apply_requirement_modifications(plan, force: true) }
.process_async_resolutions(true)
.to do
achieve { plan.syskit_has_async_resolution? }
achieve { !plan.syskit_has_async_resolution? }
end
end

it "finishes within the test the resolutions " \
"created during the execution" do
plan.add(@task_m.as_plan)
applied = false
expect_execution
.process_async_resolutions(true)
.poll do
unless applied
Syskit::Runtime.apply_requirement_modifications(
plan, force: true
)
applied = true
end
end.to do
achieve { plan.syskit_has_async_resolution? }
achieve { !plan.syskit_has_async_resolution? }
end
end

it "finishes at the end of the test resolutions " \
"created during the execution" do
plan.add(@task_m.as_plan)
expect_execution
.process_async_resolutions(true)
.poll do
Syskit::Runtime.apply_requirement_modifications(
plan, force: true
)
end
.to_achieve { plan.syskit_has_async_resolution? }

refute plan.syskit_has_async_resolution?
end
end

describe "#have_one_new_sample" do
it "passes if the task emits a sample and returns it" do
value = expect_execution { syskit_write task.in_port, 10 }
Expand Down
1 change: 0 additions & 1 deletion test/test/test_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ module Test

assert_equal false, cycles[0].planning_task_starting
assert_equal true, cycles[0].planning_task_running
assert cycles[0].has_async_resolution
end

it "waits for the planning tasks to be started before it triggers the async resolution" do
Expand Down
4 changes: 3 additions & 1 deletion test/test_instance_requirements_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

it "triggers a network resolution when started" do
task = plan.add_permanent_task(cmp_m.as_plan)
execute { task.planning_task.start! }
expect_execution { task.planning_task.start! }
.process_async_resolutions(false)
.to_run
assert plan.syskit_current_resolution
end

Expand Down
14 changes: 8 additions & 6 deletions test/test_task_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -480,12 +480,14 @@ def start_task
end

after do
if task.start_event.pending?
task.start_event.emit
end
if task.running?
expect_execution { task.stop! }
.to { emit task.stop_event }
if task
if task.start_event.pending?
task.start_event.emit
end
if task.running?
expect_execution { task.stop! }
.to { emit task.stop_event }
end
end
end

Expand Down