Module: Syskit::Test::NetworkManipulation

Included in:
ComponentTest, ProfileAssertions, Self
Defined in:
lib/syskit/test/network_manipulation.rb

Overview

Network manipulation functionality (stubs, …) useful in tests

Defined Under Namespace

Classes: CannotStub, NoConfigureFixedPoint, NoStartFixedPoint

Constant Summary collapse

@@syskit_stub_model_id =
-1

Instance Method Summary collapse

Instance Method Details

#__syskit_root_componentsObject



951
952
953
# File 'lib/syskit/test/network_manipulation.rb', line 951

def __syskit_root_components
    plan.find_tasks(Syskit::Component).not_abstract.roots(Roby::TaskStructure::Dependency)
end

#normalize_instanciation_models(to_instanciate) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/syskit/test/network_manipulation.rb', line 79

def normalize_instanciation_models(to_instanciate)
    # Instanciate all actions until we have a syskit instance
    # requirement pattern
    while true
        action_tasks, to_instanciate = to_instanciate.partition do |t|
            t.respond_to?(:planning_task) &&
                t.planning_task.pending? &&
                !t.planning_task.respond_to?(:requirements)
        end
        if action_tasks.empty?
            break
        else
            action_tasks.each do |t|
                tracker = t.as_service
                expect_execution { t.planning_task.start! }.
                    to { emit t.planning_task.start_event }
                to_instanciate << tracker.task
            end
        end
    end
    to_instanciate
end

#resolve_orocos_writer(writer) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper used to resolve writer objects



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/syskit/test/network_manipulation.rb', line 54

def resolve_orocos_writer(writer)
    if writer.respond_to?(:to_orocos_port)
        writer = Orocos.allow_blocking_calls do
            writer.to_orocos_port
        end
    end
    # We can write on LocalInputPort, LocalOutputPort and InputPort
    if writer.respond_to?(:writer)
        writer = Orocos.allow_blocking_calls do
            writer.writer
        end
    elsif !writer.respond_to?(:write)
        raise ArgumentError, "#{writer} does not seem to be a port "\
            "one can write on"
    end
    writer
end

#setupObject



14
15
16
17
18
19
# File 'lib/syskit/test/network_manipulation.rb', line 14

def setup
    @__test_overriden_configurations = Array.new
    @__test_deployment_group = Models::DeploymentGroup.new
    @__orocos_writers = Array.new
    super
end

#syskit_configure(components = __syskit_root_components, recursive: true, except: Set.new) ⇒ Object

Set this component instance up



831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
# File 'lib/syskit/test/network_manipulation.rb', line 831

def syskit_configure(components = __syskit_root_components, recursive: true, except: Set.new)
    # We need all execution agents to be started to connect (and
    # therefore configur) the tasks
    syskit_start_all_execution_agents

    components = Array(components)
    return if components.empty?

    tasks = Set.new
    except  = except.to_set
    components.each do |component|
        next if tasks.include?(component)
        syskit_prepare_configure(component, tasks, recursive: recursive, except: except)
    end
    plan = components.first.plan
    guard = syskit_guard_against_start_and_configure(tasks)

    pending = tasks.dup.to_set
    while !pending.empty?
        execute do
            Syskit::Runtime::ConnectionManagement.update(plan)
        end
        current_state = pending.size
        pending.delete_if do |t|
            t.freeze_delayed_arguments
            should_setup = Orocos.allow_blocking_calls do
                !t.setup? && t.ready_for_setup?
            end
            if should_setup
                messages = capture_log(t, :info) do
                    t.setup.execute
                    execution_engine.join_all_waiting_work
                end
                if t.failed_to_start?
                    raise t.failure_reason
                else
                    assert t.setup?, "ran the setup for #{t}, but t.setup? does not return true"
                end
                true
            else
                t.setup?
            end
        end
        if current_state == pending.size
            missing_starts = pending.flat_map do |pending_task|
                pending_task.start_event.parent_objects(Roby::EventStructure::SyskitConfigurationPrecedence).
                    find_all { |e| e.symbol == :start && !e.emitted? }
            end
            missing_starts = missing_starts.map(&:task) - pending.to_a
            if missing_starts.empty?
                raise NoConfigureFixedPoint.new(pending), "cannot configure #{pending.map(&:to_s).join(", ")}"
            else
                syskit_start(missing_starts, recursive: false)
            end
        end
    end

ensure
    if guard
        expect_execution do
            plan.remove_free_event(guard)
        end.to_run
    end
end

#syskit_configure_and_start(component = __syskit_root_components, recursive: true, except: Set.new) ⇒ Syskit::Component

Configure and start a task

Unlike #syskit_stub_deploy_configure_and_start, it does not stub the model, so model has to be deploy-able as-is.

Returns:



1139
1140
1141
1142
1143
# File 'lib/syskit/test/network_manipulation.rb', line 1139

def syskit_configure_and_start(component = __syskit_root_components, recursive: true, except: Set.new)
    syskit_configure(component, recursive: recursive, except: except)
    syskit_start(component, recursive: recursive, except: except)
    component
end

#syskit_default_stub_name(model) ⇒ Object



468
469
470
471
472
473
474
# File 'lib/syskit/test/network_manipulation.rb', line 468

def syskit_default_stub_name(model)
    model_name =
        if model.respond_to?(:name) then model.name
        else model.to_str
        end
    "stub#{syskit_stub_model_id}"
end

#syskit_deploy(*to_instanciate, add_mission: true, syskit_engine: nil, **resolve_options, &block) ⇒ Object

Run Syskit's deployer (i.e. engine) on the current plan



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/syskit/test/network_manipulation.rb', line 135

def syskit_deploy(*to_instanciate, add_mission: true, syskit_engine: nil, **resolve_options, &block)
    to_instanciate = to_instanciate.flatten # For backward-compatibility
    to_instanciate = normalize_instanciation_models(to_instanciate)

    placeholder_tasks = to_instanciate.map do |act|
        act = act.to_action if act.respond_to?(:to_action)
        plan.add(task = act.as_plan)
        plan.add_mission_task(task) if add_mission
        task
    end.compact
    root_tasks = placeholder_tasks.map(&:as_service)
    requirement_tasks = placeholder_tasks.map(&:planning_task)
    requirement_tasks.each do |task|
        task.requirements.deployment_group.use_group!(@__test_deployment_group)
    end

    not_running = requirement_tasks.find_all { |t| !t.running? }
    expect_execution { not_running.each(&:start!) }.
        to { emit *not_running.map(&:start_event) }

    resolve_options = Hash[on_error: :commit].merge(resolve_options)
    begin
        syskit_engine_resolve_handle_plan_export do
            syskit_engine ||= Syskit::NetworkGeneration::Engine.new(plan)
            syskit_engine.resolve(**resolve_options)
        end
    rescue Exception => e
        expect_execution do
            requirement_tasks.each { |t| t.failed_event.emit(e) }
        end.to do
            requirement_tasks.each do |t|
                have_error_matching Roby::PlanningFailedError.match.
                    with_origin(t)
            end
        end
        raise
    end

    execute do
        placeholder_tasks.each do |task|
            plan.remove_task(task)
        end
        requirement_tasks.each { |t| t.success_event.emit if !t.finished? }
    end

    root_tasks = root_tasks.map(&:task)
    if root_tasks.size == 1
        return root_tasks.first
    elsif root_tasks.size > 1
        return root_tasks
    end
end

#syskit_deploy_and_configure(model = subject_syskit_model, recursive: true) ⇒ Syskit::Component

Deploy and configure a model

Unlike #syskit_stub_deploy_and_configure, it does not stub the model, so model has to be deploy-able as-is.

Parameters:

  • model (#to_instance_requirements) (defaults to: subject_syskit_model)

    the requirements to deploy and configure

  • recursive (Boolean)

    if true, children of the provided model will be configured as well. Otherwise, only the toplevel task will

Returns:



1114
1115
1116
1117
1118
# File 'lib/syskit/test/network_manipulation.rb', line 1114

def syskit_deploy_and_configure(model = subject_syskit_model, recursive: true)
    root = syskit_deploy(model)
    syskit_configure(root, recursive: recursive)
    root
end

#syskit_deploy_configure_and_start(model = subject_syskit_model, recursive: true) ⇒ Syskit::Component

Deploy, configure and start a model

Unlike #syskit_stub_deploy_configure_and_start, it does not stub the model, so model has to be deploy-able as-is.

Returns:



1127
1128
1129
1130
# File 'lib/syskit/test/network_manipulation.rb', line 1127

def syskit_deploy_configure_and_start(model = subject_syskit_model, recursive: true)
    root = syskit_deploy(model)
    syskit_configure_and_start(root, recursive: recursive)
end

#syskit_engine_resolve_handle_plan_exportObject



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/syskit/test/network_manipulation.rb', line 188

def syskit_engine_resolve_handle_plan_export
    failed = false
    yield
rescue Exception
    failed = true
    raise
ensure
    if Roby.app.public_logs?
        filename = name.gsub("/", "_")
        dataflow_base, hierarchy_base = filename + "-dataflow", filename + "-hierarchy"
        if failed
            dataflow_base += "-FAILED"
            hierarchy_base += "-FAILED"
        end
        dataflow = File.join(Roby.app.log_dir, "#{dataflow_base}.svg")
        hierarchy = File.join(Roby.app.log_dir, "#{hierarchy_base}.svg")
        while File.file?(dataflow) || File.file?(hierarchy)
            i ||= 1
            dataflow = File.join(Roby.app.log_dir, "#{dataflow_base}.#{i}.svg")
            hierarchy = File.join(Roby.app.log_dir, "#{hierarchy_base}.#{i}.svg")
            i = i + 1
        end

        Graphviz.new(plan).to_file('dataflow', 'svg', dataflow)
        Graphviz.new(plan).to_file('hierarchy', 'svg', hierarchy)
    end
end

#syskit_export_to_svg(plan = self.plan, suffix: '', dataflow_options: Hash.new, hierarchy_options: Hash.new) ⇒ Object

Export the dataflow and hierarchy to SVG



1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
# File 'lib/syskit/test/network_manipulation.rb', line 1146

def syskit_export_to_svg(plan = self.plan, suffix: '', dataflow_options: Hash.new, hierarchy_options: Hash.new)
    basename = 'syskit-export-%i%s.%s.svg'

    counter = 0
    Dir.glob('syskit-export-*') do |file|
        if file =~ /syskit-export-(\d+)/
            counter = [counter, Integer($1)].max
        end
    end

    dataflow = basename % [counter + 1, suffix, 'dataflow']
    hierarchy = basename % [counter + 1, suffix, 'hierarchy']
    Syskit::Graphviz.new(plan).to_file('dataflow', 'svg', dataflow, **dataflow_options)
    Syskit::Graphviz.new(plan).to_file('hierarchy', 'svg', hierarchy, **hierarchy_options)
    puts "exported plan to #{dataflow} and #{hierarchy}"
    return dataflow, hierarchy
end

#syskit_generate_network(*to_instanciate, add_missions: true) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/syskit/test/network_manipulation.rb', line 102

def syskit_generate_network(*to_instanciate, add_missions: true)
    to_instanciate = normalize_instanciation_models(to_instanciate)
    placeholders = to_instanciate.map(&:as_plan)
    if add_missions
        execute do
            placeholders.each do |t|
                plan.add_mission_task(t)
                if t.planning_task.pending?
                    t.planning_task.start_event.call
                end
            end
        end
    end
    task_mapping = plan.in_transaction do |trsc|
        engine = NetworkGeneration::Engine.new(plan, work_plan: trsc)
        mapping = engine.compute_system_network(
            placeholders.map(&:planning_task),
            validate_generated_network: false)
        trsc.commit_transaction
        mapping
    end
    execute do
        placeholders.map do |task|
            replacement = task_mapping[task.planning_task]
            plan.replace_task(task, replacement)
            plan.remove_task(task)
            replacement.planning_task.success_event.emit
            replacement
        end
    end
end

#syskit_guard_against_configure(tasks = Array.new, guard = Roby::EventGenerator.new) ⇒ Object



928
929
930
931
932
933
934
935
936
937
# File 'lib/syskit/test/network_manipulation.rb', line 928

def syskit_guard_against_configure(tasks = Array.new, guard = Roby::EventGenerator.new)
    tasks = Array(tasks)
    plan.add_permanent_event(guard)
    plan.find_tasks(Syskit::Component).each do |t|
        if !t.setup? && !tasks.include?(t)
            t.should_configure_after(guard)
        end
    end
    guard
end

#syskit_guard_against_start_and_configure(tasks = Array.new, guard = Roby::EventGenerator.new) ⇒ Object



939
940
941
942
943
944
945
946
947
948
949
# File 'lib/syskit/test/network_manipulation.rb', line 939

def syskit_guard_against_start_and_configure(tasks = Array.new, guard = Roby::EventGenerator.new)
    plan.add_permanent_event(guard)
    syskit_guard_against_configure(tasks, guard)

    plan.find_tasks(Syskit::Component).each do |t|
        if t.pending? && !tasks.include?(t)
            t.should_start_after(guard)
        end
    end
    guard
end

#syskit_prepare_configure(component, tasks, recursive: true, except: Set.new) ⇒ Object



761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
# File 'lib/syskit/test/network_manipulation.rb', line 761

def syskit_prepare_configure(component, tasks, recursive: true, except: Set.new)
    component.freeze_delayed_arguments

    if component.respond_to?(:setup?)
        tasks << component
    end

    if recursive
        component.each_child do |child_task|
            if except.include?(child_task)
                next
            elsif child_task.respond_to?(:setup?)
                syskit_prepare_configure(child_task, tasks, recursive: true, except: except)
            end
        end
    end
end

#syskit_prepare_start(component, tasks, recursive: true, except: Set.new) ⇒ Object



912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
# File 'lib/syskit/test/network_manipulation.rb', line 912

def syskit_prepare_start(component, tasks, recursive: true, except: Set.new)
    if component.respond_to?(:setup?)
        tasks << component
    end

    if recursive
        component.each_child do |child_task|
            if except.include?(child_task)
                next
            elsif child_task.respond_to?(:setup?)
                syskit_prepare_start(child_task, tasks, recursive: true, except: except)
            end
        end
    end
end

#syskit_protect_configuration_manager(model) ⇒ Object

Ensure that any modification made to a model's configuration manager are undone at teardown



33
34
35
36
37
# File 'lib/syskit/test/network_manipulation.rb', line 33

def syskit_protect_configuration_manager(model)
    manager = model.configuration_manager
    model.configuration_manager = manager.dup
    @__test_overriden_configurations << [model, manager]
end

#syskit_start(components = __syskit_root_components, recursive: true, except: Set.new) ⇒ Object

Start this component



956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
# File 'lib/syskit/test/network_manipulation.rb', line 956

def syskit_start(components = __syskit_root_components, recursive: true, except: Set.new)
    components = Array(components)
    return if components.empty?

    tasks = Set.new
    except = except.to_set
    components.each do |component|
        next if tasks.include?(component)
        syskit_prepare_start(component, tasks, recursive: recursive, except: except)
    end
    plan = components.first.plan
    guard = syskit_guard_against_start_and_configure(tasks)

    messages = Hash.new { |h, k| h[k] = Array.new }
    tasks.each do |t|
        flexmock(t).should_receive(:info).
            and_return { |msg| messages[t] << msg }
    end

    pending = tasks.dup
    while !pending.empty?
        current_state = pending.size

        to_start = Array.new
        pending.delete_if do |t|
            if t.running?
                true
            elsif t.executable?
                if !t.setup?
                    raise "#{t} is not set up, call #syskit_configure first"
                end
                to_start << t
                true
            end
        end

        if !to_start.empty?
            expect_execution { to_start.each(&:start!) }.
                to { emit(*to_start.map(&:start_event)) }
        end

        if current_state == pending.size
            raise NoStartFixedPoint.new(pending), "cannot start #{pending.map(&:to_s).join(", ")}"
        end
    end

    messages.each do |t, messages|
        assert messages.include?("starting #{t}")
    end

    if t = tasks.find { |t| !t.running? }
        raise RuntimeError, "failed to start #{t}: starting=#{t.starting?} running=#{t.running?} finished=#{t.finished?}"
    end

ensure
    if guard
        expect_execution do
            plan.remove_free_event(guard)
        end.to_run
    end
end

#syskit_start_all_execution_agentsObject



709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
# File 'lib/syskit/test/network_manipulation.rb', line 709

def syskit_start_all_execution_agents
    guard = syskit_guard_against_configure

    agents = plan.each_task.map do |t|
        if t.execution_agent && !t.execution_agent.ready?
            t.execution_agent
        end
    end.compact

    not_running = agents.find_all { |t| !t.running? }
    not_ready   = agents.find_all { |t| !t.ready? }
    expect_execution { not_running.each(&:start!) }.
        to { emit(*not_ready.map(&:ready_event)) }

ensure
    if guard
        expect_execution do
            plan.remove_free_event(guard)
        end.to_run
    end
end

#syskit_start_execution_agents(component, recursive: true) ⇒ Object



731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
# File 'lib/syskit/test/network_manipulation.rb', line 731

def syskit_start_execution_agents(component, recursive: true)
    guard = syskit_guard_against_start_and_configure

    not_ready = []

    queue = [component]
    while !queue.empty?
        task = queue.shift
        if (agent = task.execution_agent) && !agent.ready?
            not_ready << agent
        end
        if recursive
            queue.concat task.each_child.map { |t, _| t }
        end
    end


    if !not_ready.empty?
        expect_execution do
            not_ready.each { |agent| agent.start! if !agent.running? }
        end.to { emit(*not_ready.map(&:ready_event)) }
    end
ensure
    if guard
        expect_execution do
            plan.remove_free_event(guard)
        end.to_run
    end
end

#syskit_stub(*args, **options, &block) ⇒ Object

Deprecated.

use syskit_stub_requirements instead



477
478
479
480
# File 'lib/syskit/test/network_manipulation.rb', line 477

def syskit_stub(*args, **options, &block)
    Roby.warn_deprecated "syskit_stub has been renamed to syskit_stub_requirements to make the difference with syskit_stub_network more obvious"
    syskit_stub_requirements(*args, **options, &block)
end

#syskit_stub_and_deploy(model = subject_syskit_model, recursive: true, remote_task: self.syskit_stub_resolves_remote_tasks?, &block) ⇒ Object

Deploy the given composition, replacing every single data service and task context by a ruby task context, allowing to then test.

Examples:

reuse toplevel tasks in children-of-children

class Cmp < Syskit::Composition
   add PoseSrv, :as => 'pose'
end
class RootCmp < Syskit::Composition
   add PoseSrv, :as => 'pose'
   add Cmp, :as => 'processor'
end
model = RootCmp.use(
   'processor' => Cmp.use('pose' => RootCmp.pose_child))
syskit_stub_deploy_and_start_composition(model)

Parameters:

  • recursive (Boolean)

    (false) if true, the method will stub the children of compositions that are used by the root composition. Otherwise, you have to refer to them in the original instance requirements



1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
# File 'lib/syskit/test/network_manipulation.rb', line 1052

def syskit_stub_and_deploy(
    model = subject_syskit_model, recursive: true,
        remote_task: self.syskit_stub_resolves_remote_tasks?, &block)

    if model.respond_to?(:to_str)
        model = syskit_stub_task_context_model(model, &block)
    end
    tasks = syskit_generate_network(*model, &block)
    tasks = syskit_stub_network(tasks, remote_task: remote_task)
    if model.respond_to?(:to_ary)
        tasks
    else
        tasks.first
    end
end

#syskit_stub_attached_device(bus, as: syskit_default_stub_name(bus)) ⇒ Object

Create a stub device attached on the given bus

If the bus is a device object, the new device is attached to the same robot model. Otherwise, a new robot model is created for both the bus and the device

Parameters:

  • bus (Model<ComBus>, MasterDeviceInstance)

    either a bus model or a bus object

  • as (String)

    a name for the new device

  • driver (Model<TaskContext>)

    the driver that should be used for the device. If not given, syskit will look for a suitable driver or stub one



435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/syskit/test/network_manipulation.rb', line 435

def syskit_stub_attached_device(bus, as: syskit_default_stub_name(bus))
    if !bus.kind_of?(Robot::DeviceInstance)
        bus = syskit_stub_com_bus(bus, as: "#{as}_bus")
    end
    bus_m = bus.model
    dev_m = Syskit::Device.new_submodel(name: "#{bus}-stub") do
        provides bus_m::ClientSrv
    end
    dev = syskit_stub_device(dev_m, as: as)
    dev.attach_to(bus)
    dev
end

#syskit_stub_com_bus(model, as: syskit_default_stub_name(model), driver: nil, robot: nil, **device_options) ⇒ Object

Create a stub combus of the given model

It is created on a new robot instance so that to avoid clashes

Parameters:

  • model (Model<ComBus>)

    the device model

  • as (String)

    the combus name

  • driver (Model<TaskContext>)

    the driver that should be used. If not given, a new driver is stubbed



417
418
419
420
421
# File 'lib/syskit/test/network_manipulation.rb', line 417

def syskit_stub_com_bus(model, as: syskit_default_stub_name(model), driver: nil, robot: nil, **device_options)
    robot ||= Syskit::Robot::RobotDefinition.new
    driver ||= syskit_stub_driver_model_for(model)
    robot.com_bus(model, as: as, using: driver, **device_options)
end

#syskit_stub_component(model, devices: true) ⇒ Object



291
292
293
294
295
296
297
# File 'lib/syskit/test/network_manipulation.rb', line 291

def syskit_stub_component(model, devices: true)
    if devices
        syskit_stub_required_devices(model)
    else
        model
    end
end

#syskit_stub_composition_requirements(model, recursive: true, as: syskit_default_stub_name(model), devices: true) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper for #syskit_stub_model

Parameters:



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/syskit/test/network_manipulation.rb', line 358

def syskit_stub_composition_requirements(model, recursive: true, as: syskit_default_stub_name(model), devices: true)
    model = syskit_stub_component(model, devices: devices)

    if recursive
        model.each_child do |child_name, selected_child|
            if selected_task = selected_child.component
                deployed_child = selected_task
            else
                child_model = selected_child.selected
                selected_service = child_model.service
                child_model = child_model.to_component_model
                if child_model.composition_model?
                    deployed_child = syskit_stub_composition_requirements(
                        child_model, recursive: true, as: "#{as}_#{child_name}", devices: devices)
                else
                    deployed_child = syskit_stub_task_context_requirements(
                        child_model, as: "#{as}_#{child_name}", devices: devices)
                end
                if selected_service
                    deployed_child.select_service(selected_service)
                end
            end
            model.use(child_name => deployed_child)
        end
    end

    model
end

#syskit_stub_conf(task_m, *conf, data: Hash.new) ⇒ Object

Create empty configuration sections for the given task model



345
346
347
348
349
350
351
# File 'lib/syskit/test/network_manipulation.rb', line 345

def syskit_stub_conf(task_m, *conf, data: Hash.new)
    concrete_task_m = task_m.concrete_model
    syskit_protect_configuration_manager(concrete_task_m)
    conf.each do |conf_name|
        concrete_task_m.configuration_manager.add(conf_name, data, merge: true)
    end
end

#syskit_stub_configured_deployment(task_model = nil, name = nil, remote_task: syskit_stub_resolves_remote_tasks?, , register: true, &block) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/syskit/test/network_manipulation.rb', line 226

def syskit_stub_configured_deployment(task_model = nil, name = nil,
    remote_task: syskit_stub_resolves_remote_tasks?, register: true, &block)

    if task_model
        task_model = task_model.to_component_model
    end

    process_server = Syskit.conf.process_server_for('stubs')

    task_context_class =
        if remote_task
            Orocos::RubyTasks::RemoteTaskContext
        else
            process_server.task_context_class
        end

    name ||= syskit_default_stub_name(task_model)
    deployment_model = Deployment.new_submodel(name: name) do
        if task_model
            task(name, task_model.orogen_model)
        end
        if block_given?
            instance_eval(&block)
        end
    end

    deployment = Models::ConfiguredDeployment.new(
        'stubs', deployment_model, Hash[name => name], name,
        Hash[task_context_class: task_context_class])
    if register
        @__test_deployment_group.register_configured_deployment(deployment)
    end
    deployment
end

#syskit_stub_deploy_and_configure(model = subject_syskit_model, recursive: true, as: syskit_default_stub_name(model), remote_task: self.syskit_stub_resolves_remote_tasks?, &block) ⇒ Syskit::Component

Stub a task, deploy it and configure it

This starts the underlying (stubbed) deployment process

Returns:

See Also:



1075
1076
1077
1078
1079
1080
1081
1082
1083
# File 'lib/syskit/test/network_manipulation.rb', line 1075

def syskit_stub_deploy_and_configure(
        model = subject_syskit_model, recursive: true,
        as: syskit_default_stub_name(model),
        remote_task: self.syskit_stub_resolves_remote_tasks?, &block)

    root = syskit_stub_and_deploy(model, recursive: recursive, remote_task: remote_task, &block)
    syskit_configure(root, recursive: recursive)
    root
end

#syskit_stub_deploy_configure_and_start(model = subject_syskit_model, recursive: true, as: syskit_default_stub_name(model), remote_task: self.syskit_stub_resolves_remote_tasks?, &block) ⇒ Syskit::Component

Stub a task, deploy it, configure it and start the task and the underlying stub deployment

This starts the underlying (stubbed) deployment process

Returns:

See Also:



1093
1094
1095
1096
1097
1098
1099
1100
1101
# File 'lib/syskit/test/network_manipulation.rb', line 1093

def syskit_stub_deploy_configure_and_start(
        model = subject_syskit_model, recursive: true,
        as: syskit_default_stub_name(model),
        remote_task: self.syskit_stub_resolves_remote_tasks?, &block)

    root = syskit_stub_and_deploy(model, recursive: recursive, remote_task: remote_task, &block)
    syskit_configure_and_start(root, recursive: recursive)
    root
end

#syskit_stub_deployment(name = "deployment", deployment_model = nil, remote_task: self.syskit_stub_resolves_remote_tasks?, &block) ⇒ Object

Create a new stub deployment instance, optionally stubbing the model as well



283
284
285
286
287
288
289
# File 'lib/syskit/test/network_manipulation.rb', line 283

def syskit_stub_deployment(
        name = "deployment", deployment_model = nil,
        remote_task: self.syskit_stub_resolves_remote_tasks?, &block)
    deployment_model ||= syskit_stub_deployment_model(nil, name, &block)
    plan.add_permanent_task(task = deployment_model.new(process_name: name, on: 'stubs'))
    task
end

#syskit_stub_deployment_model(task_model = nil, name = nil, remote_task: self.syskit_stub_resolves_remote_tasks?) { ... } ⇒ Models::ConfiguredDeployment

Create a new stub deployment model that can deploy a given task context model

Parameters:

  • task_model (Model<Syskit::TaskContext>, nil) (defaults to: nil)

    if given, a task model that should be deployed by this deployment model

  • name (String) (defaults to: nil)

    the name of the deployed task as well as of the deployment. If not given, and if task_model is provided, task_model.name is used as default

Yields:

  • the deployment model context, i.e. a context in which the same declarations than in oroGen's #deployment statement are available

Returns:



273
274
275
276
277
278
279
# File 'lib/syskit/test/network_manipulation.rb', line 273

def syskit_stub_deployment_model(
        task_model = nil, name = nil,
        remote_task: self.syskit_stub_resolves_remote_tasks?, &block)
    configured_deployment = syskit_stub_configured_deployment(task_model,
        name, remote_task: remote_task, &block)
    configured_deployment.model
end

#syskit_stub_device(model, as: syskit_default_stub_name(model), driver: nil, robot: nil, **device_options) ⇒ Object

Create a stub device of the given model

It is created on a new robot instance so that to avoid clashes

Parameters:

  • model (Model<Device>)

    the device model

  • as (String)

    the device name

  • driver (Model<TaskContext>)

    the driver that should be used. If not given, a new driver is stubbed



403
404
405
406
407
# File 'lib/syskit/test/network_manipulation.rb', line 403

def syskit_stub_device(model, as: syskit_default_stub_name(model), driver: nil, robot: nil, **device_options)
    robot ||= Syskit::Robot::RobotDefinition.new
    driver ||= syskit_stub_driver_model_for(model)
    robot.device(model, as: as, using: driver, **device_options)
end

#syskit_stub_driver_model_for(model) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Finds a driver model for a given device model, or create one if there is none



391
392
393
# File 'lib/syskit/test/network_manipulation.rb', line 391

def syskit_stub_driver_model_for(model)
    syskit_stub_requirements(model.find_all_drivers.first || model, devices: false)
end

#syskit_stub_model_idObject



461
462
463
464
465
466
# File 'lib/syskit/test/network_manipulation.rb', line 461

def syskit_stub_model_id
    id = (@@syskit_stub_model_id += 1)
    if id != 0
        id
    end
end

#syskit_stub_network(root_tasks, remote_task: self.syskit_stub_resolves_remote_tasks?) ⇒ Object

Stub an already existing network



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# File 'lib/syskit/test/network_manipulation.rb', line 529

def syskit_stub_network(root_tasks, remote_task: self.syskit_stub_resolves_remote_tasks?)
    tasks = Set.new
    dependency_graph = plan.task_relation_graph_for(Roby::TaskStructure::Dependency)
    root_tasks = Array(root_tasks).map do |t|
        tasks << t
        dependency_graph.depth_first_visit(t) do |child_t|
            tasks << child_t
        end

        if plan.mission_task?(t)
            [t, :mission_task]
        elsif plan.permanent_task?(t)
            [t, :permanent_task]
        else
            [t]
        end
    end

    mapped_tasks = Hash.new
    # NOTE: must NOT call #apply_merge_group with merge_mappings
    # directly. #apply_merge_group "replaces" the subnet represented
    # by the keys with the subnet represented by the values. In
    # other words, the connections present between two keys would
    # NOT be copied between the corresponding values
    plan.in_transaction do |trsc|
        trsc_tasks = tasks.map { |t| trsc[t] }

        merge_solver = NetworkGeneration::MergeSolver.new(trsc)
        tasks.each do |plan_t|
            merge_solver.register_replacement(plan_t, trsc[plan_t])
        end
        merge_mappings = Hash.new
        stubbed_tags = Hash.new
        trsc_tasks.each do |task|
            task.model.each_master_driver_service do |srv|
                task.arguments[:"#{srv.name}_dev"] ||=
                    syskit_stub_device(srv.model, driver: srv)
            end
        end

        trsc_tasks.find_all(&:abstract?).each do |abstract_task|
            # The task is required as being abstract (usually a
            # if_already_present tag). Do not stub that
            next if abstract_task.requirements.abstract?

            concrete_task =
                if abstract_task.kind_of?(Syskit::Actions::Profile::Tag)
                    tag_id = [abstract_task.model.tag_name, abstract_task.model.profile.name]
                    stubbed_tags[tag_id] ||= syskit_stub_network_abstract_component(abstract_task)
                else
                    syskit_stub_network_abstract_component(abstract_task)
                end

            if abstract_task.placeholder? && !abstract_task.kind_of?(Syskit::TaskContext) # 'pure' proxied data services
                trsc.replace_task(abstract_task, concrete_task)
                merge_solver.register_replacement(abstract_task, concrete_task)
            else
                merge_mappings[abstract_task] = concrete_task
            end
        end
        merge_mappings.each do |original, replacement|
            unless original.can_merge?(replacement)
                raise CannotStub.new(original, replacement),
                    "cannot stub #{original} with #{replacement}, maybe "\
                    "some delayed arguments are not set ?"
            end
            merge_solver.apply_merge_group(original => replacement)
        end
        merge_solver.merge_identical_tasks

        merge_mappings = Hash.new
        trsc_tasks.each do |original_task|
            concrete_task = merge_solver.replacement_for(original_task)
            if concrete_task.kind_of?(TaskContext) && !concrete_task.execution_agent
                merge_mappings[concrete_task] = syskit_stub_network_deployment(concrete_task, remote_task: remote_task)
            end
        end
        merge_mappings.each do |original, replacement|
            unless original.can_merge?(replacement)
                raise CannotStub.new(original, replacement),
                    "cannot stub #{original} with #{replacement}, maybe "\
                    "some delayed arguments are not set ?"
            end
            merge_solver.apply_merge_group(original => replacement)
        end

        mapped_tasks = Hash.new
        tasks.each do |plan_t|
            replacement_t = merge_solver.replacement_for(plan_t)
            mapped_tasks[plan_t] = trsc.may_unwrap(replacement_t)
        end

        root_tasks.each do |root_t, status|
            replacement_t = mapped_tasks[root_t]
            if replacement_t != root_t
                unless replacement_t.planning_task
                    replacement_t.planned_by trsc[root_t.planning_task]
                end
                trsc.send("add_#{status}", replacement_t)
            end
        end

        NetworkGeneration::SystemNetworkGenerator.remove_abstract_composition_optional_children(trsc)
        trsc.static_garbage_collect
        NetworkGeneration::SystemNetworkGenerator.verify_task_allocation(trsc)
        trsc.commit_transaction
    end


    execute do
        mapped_tasks.each do |old, new|
            if old != new
                plan.remove_task(old)
            end
        end
    end
    root_tasks.map { |t, _| mapped_tasks[t] }
end

#syskit_stub_network_abstract_component(task) ⇒ Object



672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
# File 'lib/syskit/test/network_manipulation.rb', line 672

def syskit_stub_network_abstract_component(task)
    task_m = task.concrete_model
    if task_m.placeholder?
        task_m = syskit_stub_placeholder(task_m)
    elsif task_m.abstract?
        task_m = task_m.new_submodel(name: "#{task_m.name}-stub")
    end

    arguments = task.arguments.dup
    task_m.each_master_driver_service do |srv|
        arguments[:"#{srv.name}_dev"] ||=
            syskit_stub_device(srv.model, driver: task_m)
    end
    task_m.new(**arguments)
end

#syskit_stub_network_deployment(task, as: task.orocos_name || syskit_default_stub_name(task.model), remote_task: self.syskit_stub_resolves_remote_tasks?) ⇒ Object



688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
# File 'lib/syskit/test/network_manipulation.rb', line 688

def syskit_stub_network_deployment(
        task, as: task.orocos_name || syskit_default_stub_name(task.model),
        remote_task: self.syskit_stub_resolves_remote_tasks?)

    task_m = task.concrete_model
    deployment_model = syskit_stub_configured_deployment(
        task_m, as, remote_task: remote_task, register: false)
    syskit_stub_conf(task_m, *task.arguments[:conf])
    task.plan.add(deployer = deployment_model.new)
    deployed_task = deployer.instanciate_all_tasks.first

    new_args = Hash.new
    task.arguments.find_all do |key, arg|
        if deployed_task.arguments.writable?(key, arg)
            new_args[key] = arg
        end
    end
    deployed_task.assign_arguments(**new_args)
    deployed_task
end

#syskit_stub_placeholder(model) ⇒ Object



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
# File 'lib/syskit/test/network_manipulation.rb', line 648

def syskit_stub_placeholder(model)
    superclass = if model.superclass <= Syskit::TaskContext
                     model.superclass
                 else Syskit::TaskContext
                 end

    services = model.proxied_data_service_models
    task_m = superclass.new_submodel(name: "#{model.to_s}-stub")
    services.each_with_index do |srv, idx|
        srv.each_input_port do |p|
            task_m.orogen_model.input_port p.name, Orocos.find_orocos_type_name_by_type(p.type)
        end
        srv.each_output_port do |p|
            task_m.orogen_model.output_port p.name, Orocos.find_orocos_type_name_by_type(p.type)
        end
        if srv <= Syskit::Device
            task_m.driver_for srv, as: "dev#{idx}"
        else
            task_m.provides srv, as: "srv#{idx}"
        end
    end
    task_m
end

#syskit_stub_required_devices(model) ⇒ Object

Stubs the devices required by the given model



449
450
451
452
453
454
455
456
457
# File 'lib/syskit/test/network_manipulation.rb', line 449

def syskit_stub_required_devices(model)
    model = model.to_instance_requirements
    model.model.to_component_model.each_master_driver_service do |srv|
        if !model.arguments[:"#{srv.name}_dev"]
            model.with_arguments(:"#{srv.name}_dev" => syskit_stub_device(srv.model, driver: model.model))
        end
    end
    model
end

#syskit_stub_requirements(model = subject_syskit_model, recursive: true, as: syskit_default_stub_name(model), devices: true, &block) ⇒ Object

Create an InstanceRequirement instance that would allow to deploy the given model



484
485
486
487
488
489
490
491
492
493
494
495
# File 'lib/syskit/test/network_manipulation.rb', line 484

def syskit_stub_requirements(model = subject_syskit_model, recursive: true, as: syskit_default_stub_name(model), devices: true, &block)
    if model.respond_to?(:to_str)
        model = syskit_stub_task_context_model(model, &block)
    end
    model = model.to_instance_requirements.dup

    if model.composition_model?
        syskit_stub_composition_requirements(model, recursive: recursive, as: as, devices: devices)
    else
        syskit_stub_task_context_requirements(model, as: as, devices: devices)
    end
end

#syskit_stub_resolves_remote_tasks=(value) ⇒ Object

Whether (false) the stub methods should resolve ruby tasks as ruby tasks (i.e. Orocos::RubyTasks::TaskContext, the default), or (true) as something that looks more like a remote task (Orocos::RubyTasks::RemoteTaskContext)

The latter is used in Syskit's own test suite to ensure that we don't call remote methods from within Syskit's own event loop



12
# File 'lib/syskit/test/network_manipulation.rb', line 12

attr_predicate :syskit_stub_resolves_remote_tasks?, true

#syskit_stub_resolves_remote_tasks?Boolean

Whether (false) the stub methods should resolve ruby tasks as ruby tasks (i.e. Orocos::RubyTasks::TaskContext, the default), or (true) as something that looks more like a remote task (Orocos::RubyTasks::RemoteTaskContext)

The latter is used in Syskit's own test suite to ensure that we don't call remote methods from within Syskit's own event loop

Returns:

  • (Boolean)


12
# File 'lib/syskit/test/network_manipulation.rb', line 12

attr_predicate :syskit_stub_resolves_remote_tasks?, true

#syskit_stub_task_context_model(name) { ... } ⇒ Object

Create a new task context model with the given name

Yields:

  • a block in which the task context interface can be defined



220
221
222
223
224
# File 'lib/syskit/test/network_manipulation.rb', line 220

def syskit_stub_task_context_model(name, &block)
    model = TaskContext.new_submodel(name: name, &block)
    model.orogen_model.extended_state_support
    model
end

#syskit_stub_task_context_requirements(model, as: syskit_default_stub_name(model), devices: true) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper for #syskit_stub_and_deploy

Parameters:



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
# File 'lib/syskit/test/network_manipulation.rb', line 305

def syskit_stub_task_context_requirements(model, as: syskit_default_stub_name(model), devices: true)
    model = model.to_instance_requirements

    task_m = model.model.to_component_model.concrete_model
    if task_m.placeholder?
        superclass = if task_m.superclass <= Syskit::TaskContext
                         task_m.superclass
                     else Syskit::TaskContext
                     end

        services = task_m.proxied_data_service_models
        task_m = superclass.new_submodel(name: "#{task_m.to_s}-stub")
        services.each_with_index do |srv, idx|
            srv.each_input_port do |p|
                task_m.orogen_model.input_port p.name, Orocos.find_orocos_type_name_by_type(p.type)
            end
            srv.each_output_port do |p|
                task_m.orogen_model.output_port p.name, Orocos.find_orocos_type_name_by_type(p.type)
            end
            if srv <= Syskit::Device
                task_m.driver_for srv, as: "dev#{idx}"
            else
                task_m.provides srv, as: "srv#{idx}"
            end
        end
    elsif task_m.abstract?
        task_m = task_m.new_submodel(name: "#{task_m.name}-stub")
    end
    model.add_models([task_m])
    model = syskit_stub_component(model, devices: devices)

    syskit_stub_conf(task_m, *model.arguments[:conf])

    deployment = syskit_stub_configured_deployment(task_m, as, register: false)
    model.reset_deployment_selection
    model.use_configured_deployment(deployment)
    model
end

#syskit_wait_ready(writer_or_reader, component: writer_or_reader.port.to_actual_port.component) ⇒ Object



1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
# File 'lib/syskit/test/network_manipulation.rb', line 1018

def syskit_wait_ready(writer_or_reader, component: writer_or_reader.port.to_actual_port.component)
    return if writer_or_reader.ready?

    if !component.setup?
        syskit_configure(component)
    end
    if !component.running?
        syskit_start(component)
    end

    expect_execution.to do
        achieve { writer_or_reader.ready? }
    end
end

#syskit_write(writer, sample) ⇒ Object

Write a sample on a given input port



73
74
75
76
77
# File 'lib/syskit/test/network_manipulation.rb', line 73

def syskit_write(writer, sample)
    writer = resolve_orocos_writer(writer)
    @__orocos_writers << writer if writer.respond_to?(:disconnect)
    writer.write(sample)
end

#teardownObject



21
22
23
24
25
26
27
28
29
# File 'lib/syskit/test/network_manipulation.rb', line 21

def teardown
    @__orocos_writers.each do |w|
        w.disconnect
    end
    super
    @__test_overriden_configurations.each do |model, manager|
        model.configuration_manager = manager
    end
end

#use_deployment(*args, **options) ⇒ Object



39
40
41
# File 'lib/syskit/test/network_manipulation.rb', line 39

def use_deployment(*args, **options)
    @__test_deployment_group.use_deployment(*args, **options)
end

#use_ruby_tasks(*args, **options) ⇒ Object



43
44
45
# File 'lib/syskit/test/network_manipulation.rb', line 43

def use_ruby_tasks(*args, **options)
    @__test_deployment_group.use_ruby_tasks(*args, **options)
end

#use_unmanaged_task(*args, **options) ⇒ Object



47
48
49
# File 'lib/syskit/test/network_manipulation.rb', line 47

def use_unmanaged_task(*args, **options)
    @__test_deployment_group.use_unmanaged_task(*args, **options)
end