Module: Syskit::Test::ProfileAssertions

Includes:
NetworkManipulation
Included in:
ActionInterfaceTest, ActionTest, ProfileTest
Defined in:
lib/syskit/test/profile_assertions.rb

Overview

Defines assertions for definitions (Syskit::Actions::Profile) or actions that are created from these definitions (Roby::Actions::Interface)

It assumes that the test class was extended using ProfileModelAssertions

Defined Under Namespace

Classes: ProfileAssertionFailed

Instance Method Summary collapse

Methods included from NetworkManipulation

#__syskit_root_components, #normalize_instanciation_models, #resolve_orocos_writer, #setup, #syskit_configure, #syskit_configure_and_start, #syskit_default_stub_name, #syskit_deploy, #syskit_deploy_and_configure, #syskit_deploy_configure_and_start, #syskit_engine_resolve_handle_plan_export, #syskit_export_to_svg, #syskit_generate_network, #syskit_guard_against_configure, #syskit_guard_against_start_and_configure, #syskit_prepare_configure, #syskit_prepare_start, #syskit_protect_configuration_manager, #syskit_start, #syskit_start_all_execution_agents, #syskit_start_execution_agents, #syskit_stub, #syskit_stub_and_deploy, #syskit_stub_attached_device, #syskit_stub_com_bus, #syskit_stub_component, #syskit_stub_composition_requirements, #syskit_stub_conf, #syskit_stub_configured_deployment, #syskit_stub_deploy_and_configure, #syskit_stub_deploy_configure_and_start, #syskit_stub_deployment, #syskit_stub_deployment_model, #syskit_stub_device, #syskit_stub_driver_model_for, #syskit_stub_model_id, #syskit_stub_network, #syskit_stub_network_abstract_component, #syskit_stub_network_deployment, #syskit_stub_placeholder, #syskit_stub_required_devices, #syskit_stub_requirements, #syskit_stub_resolves_remote_tasks=, #syskit_stub_resolves_remote_tasks?, #syskit_stub_task_context_model, #syskit_stub_task_context_requirements, #syskit_wait_ready, #syskit_write, #teardown, #use_deployment, #use_ruby_tasks, #use_unmanaged_task

Instance Method Details

#Actions(arg) ⇒ Object

Validates an argument that can be an action, an action collection (e.g. a profile) or an array of action, and normalizes it into an array of actions

Raises:

  • (ArgumentError)

    if the argument is invalid



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/syskit/test/profile_assertions.rb', line 36

def Actions(arg)
    if arg.respond_to?(:each_action)
        arg.each_action.map(&:to_action)
    elsif arg.respond_to?(:to_action)
        [arg.to_action]
    elsif arg.respond_to?(:flat_map)
        arg.flat_map { |a| Actions(a) }
    else
        raise ArgumentError, "expected an action or a collection of actions, but got #{arg}"
    end
end

#assert_can_configure_together(*actions) ⇒ Object

Tests that the given syskit-generated actions can be deployed together and that the task contexts #configure method can be called successfully

It requires running the actual deployments, even though the components themselve never get started

It is stronger (and therefore includes) #assert_can_deploy_together



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/syskit/test/profile_assertions.rb', line 278

def assert_can_configure_together(*actions)
    if actions.empty?
        actions = subject_syskit_model
    end
    self.assertions += 1
    roots = assert_can_deploy_together(*AtomicActions(actions))
    # assert_can_deploy_together has one of its idiotic return
    # interface that returns either a single task if a single action
    # was given, or an array otherwise. I'd like to have someone
    # to talk me out of this kind of ideas.
    tasks = plan.compute_useful_tasks(Array(roots))
    task_contexts = tasks.find_all { |t| t.kind_of?(Syskit::TaskContext) }.
        each do |task_context|
            if !task_context.plan
                raise ProfileAssertionFailed.new(actions, nil), "#{task_context} got garbage-collected before it got configured"
            end
        end
    syskit_configure(task_contexts)
    roots
rescue Exception => e
    raise ProfileAssertionFailed.new(actions, e), e.message
end

#assert_can_deploy(action_or_profile = subject_syskit_model, exclude: []) ⇒ Object

Tests that the following syskit-generated actions can be deployed, that is they result in a valid, non-abstract network whose all components have a deployment

If given a profile, it will perform the test on each action of the profile taken in isolation. If you want to test whether actions can be deployed at the same time, use #assert_can_deploy_together

If called without argument, it tests the spec's context profile



220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/syskit/test/profile_assertions.rb', line 220

def assert_can_deploy(action_or_profile = subject_syskit_model, exclude: [])
    actions, skipped_actions = BulkAssertAtomicActions(action_or_profile, exclude: exclude)
    if !skipped_actions.empty?
        flunk "could not validate #{skipped_actions.size} non-Syskit actions: #{skipped_actions.map(&:name).sort.join(", ")}, pass them to the 'exclude' argument to #{__method__}"
    end

    actions.each do |action|
        task = assert_can_deploy_together(action)
        plan.unmark_mission_task(task)
        expect_execution.garbage_collect(true).to_run
    end
end

#assert_can_deploy_together(*actions) ⇒ Object

Tests that the given syskit-generated actions can be deployed together

It is stronger (and therefore includes) #assert_can_instanciate_together



247
248
249
250
251
252
253
254
255
256
257
# File 'lib/syskit/test/profile_assertions.rb', line 247

def assert_can_deploy_together(*actions)
    if actions.empty?
        actions = subject_syskit_model
    end
    self.assertions += 1
    syskit_deploy(AtomicActions(actions),
                     compute_policies: true,
                     compute_deployments: true)
rescue Exception => e
    raise ProfileAssertionFailed.new(actions, e), e.message
end

#assert_can_instanciate(action_or_profile = subject_syskit_model, exclude: []) ⇒ Object

Tests that the following definition can be successfully instanciated in a valid, non-abstract network.

If given a profile, it will perform the test on each action of the profile taken in isolation. If you want to test whether actions can be instanciated at the same time, use #assert_can_instanciate_together

If called without argument, it tests the spec's context profile



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/syskit/test/profile_assertions.rb', line 143

def assert_can_instanciate(action_or_profile = subject_syskit_model, exclude: [])
    actions, skipped_actions = BulkAssertAtomicActions(action_or_profile, exclude: exclude)
    if !skipped_actions.empty?
        flunk "could not validate #{skipped_actions.size} non-Syskit actions: #{skipped_actions.map(&:name).sort.join(", ")}, pass them to the 'exclude' argumet to #{__method__}"
    end

    actions.each do |action|
        task = assert_can_instanciate_together(action)
        plan.unmark_mission_task(task)
        expect_execution.garbage_collect(true).to_run
    end
end

#assert_can_instanciate_together(*actions) ⇒ Object

Tests that the given syskit-generated actions can be instanciated together, i.e. that the resulting network is valid and non-abstract (does not contain abstract tasks or data services)

Note that it passes even though the resulting network cannot be deployed (e.g. if some components do not have a corresponding deployment)



173
174
175
176
177
178
179
180
181
182
183
# File 'lib/syskit/test/profile_assertions.rb', line 173

def assert_can_instanciate_together(*actions)
    if actions.empty?
        actions = subject_syskit_model
    end
    self.assertions += 1
    syskit_deploy(AtomicActions(actions),
                     compute_policies: false,
                     compute_deployments: false)
rescue Exception => e
    raise ProfileAssertionFailed.new(actions, e), e.message
end

#assert_is_self_contained(action_or_profile = subject_syskit_model, message: "%s is not self contained", exclude: [], **instanciate_options) ⇒ Object

Tests that a definition or all definitions of a profile are self-contained, that is that the only variation points in the profile are profile tags.

If given a profile as argument, or no profile at all, will test on all definitions of resp. the given profile or the test's subject

Note that it is a really good idea to maintain this property. No. Seriously. Keep it in your tests.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/syskit/test/profile_assertions.rb', line 91

def assert_is_self_contained(action_or_profile = subject_syskit_model, message: "%s is not self contained", exclude: [], **instanciate_options)
    actions, skipped_actions = BulkAssertAtomicActions(action_or_profile, exclude: exclude)
    if !skipped_actions.empty?
        flunk "could not validate #{skipped_actions.size} non-Syskit actions: #{skipped_actions.map(&:name).sort.join(", ")}, pass them to the 'exclude' argumet to #{__method__}"
    end

    actions.each do |act|
        begin
            self.assertions += 1
            syskit_engine = Syskit::NetworkGeneration::Engine.new(plan)
            task = syskit_deploy(act, syskit_engine: syskit_engine,
                                 compute_policies: false, compute_deployments: false,
                                 validate_generated_network: false, **instanciate_options)
            # Get rid of all the tasks that 
            still_abstract = plan.find_local_tasks(Syskit::Component).
                abstract.to_set
            still_abstract &= plan.compute_useful_tasks([task])
            tags, other = still_abstract.partition { |task| task.class <= Actions::Profile::Tag }
            tags_from_other = tags.find_all { |task| task.class.profile != subject_syskit_model }
            if !other.empty?
                raise Roby::Test::Assertion.new(TaskAllocationFailed.new(syskit_engine, other)), message % [act.to_s]
            elsif !tags_from_other.empty?
                other_profiles = tags_from_other.map { |t| t.class.profile }.uniq
                raise Roby::Test::Assertion.new(TaskAllocationFailed.new(syskit_engine, tags)), "#{act} contains tags from another profile (found #{other_profiles.map(&:name).sort.join(", ")}, expected #{subject_syskit_model}"
            end
            plan.unmark_mission_task(task)
            expect_execution.garbage_collect(true).to_run
        rescue Exception => e
            raise ProfileAssertionFailed.new(act, e), e.message
        end
    end
end

#AtomicActions(arg, &block) ⇒ Object

Like #Actions, but expands coordination models into their consistuent actions



50
51
52
53
54
# File 'lib/syskit/test/profile_assertions.rb', line 50

def AtomicActions(arg, &block)
    Actions(arg).flat_map do |action|
        expand_coordination_models(action)
    end
end

#BulkAssertAtomicActions(arg, exclude: [], &block) ⇒ Object

Like #AtomicActions but filters out actions that cannot be handled by the bulk assertions, and returns them

Parameters:

  • arg (Array, Action)

    the action that is expanded

  • actions (Array<Roby::Actions::Action>)

    that should be ignored. Actions are compared on the basis of their model (arguments do not count)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/syskit/test/profile_assertions.rb', line 63

def BulkAssertAtomicActions(arg, exclude: [], &block)
    exclude = Actions(exclude).map(&:model)
    skipped_actions = Array.new
    actions = AtomicActions(arg).find_all do |action|
        if exclude.include?(action.model)
            false
        elsif !action.kind_of?(Actions::Action) && action.has_missing_required_arg?
            skipped_actions << action
            false
        else
            true
        end
    end
    skipped_actions.delete_if do |skipped_action|
        actions.any? { |action| action.model == skipped_action.model }
    end
    return actions, skipped_actions
end

#can_configure_together(*actions) ⇒ Object

Spec-style call for #assert_can_configure_together



302
303
304
# File 'lib/syskit/test/profile_assertions.rb', line 302

def can_configure_together(*actions)
    assert_can_configure_together(*actions)
end

#can_deploy(action_or_profile = subject_syskit_model) ⇒ Object

Spec-style call for #assert_can_deploy

Examples:

verify that each definition of a profile can be deployed

describe MyBundle::Profiles::MyProfile do
  it { can_deploy }
end


239
240
241
# File 'lib/syskit/test/profile_assertions.rb', line 239

def can_deploy(action_or_profile = subject_syskit_model)
    assert_can_deploy(action_or_profile)
end

#can_deploy_together(*actions) ⇒ Object

Spec-style call for #assert_can_deploy_together

Examples:

verify that all definitions of a profile can be deployed at the same time

describe MyBundle::Profiles::MyProfile do
  it { can_deploy_together }
end


265
266
267
# File 'lib/syskit/test/profile_assertions.rb', line 265

def can_deploy_together(*actions)
    assert_can_deploy_together(*actions)
end

#can_instanciate(action_or_profile = subject_syskit_model) ⇒ Object

Spec-style call for #assert_can_instanciate

Examples:

verify that all definitions of a profile can be instanciated

describe MyBundle::Profiles::MyProfile do
  it { can_instanciate }
end


162
163
164
# File 'lib/syskit/test/profile_assertions.rb', line 162

def can_instanciate(action_or_profile = subject_syskit_model)
    assert_can_instanciate(action_or_profile)
end

#can_instanciate_together(*actions) ⇒ Object

Spec-style call for #assert_can_instanciate_together

Examples:

verify that all definitions of a profile can be instanciated all at the same time

describe MyBundle::Profiles::MyProfile do
  it { can_instanciate_together }
end


191
192
193
# File 'lib/syskit/test/profile_assertions.rb', line 191

def can_instanciate_together(*actions)
    assert_can_instanciate_together(*actions)
end

#expand_coordination_models(action) ⇒ 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.

Given an action, returns the list of atomic actions it refers to



198
199
200
201
202
203
204
205
206
207
208
# File 'lib/syskit/test/profile_assertions.rb', line 198

def expand_coordination_models(action)
    if action.model.respond_to?(:coordination_model)
        actions = action.model.coordination_model.each_task.flat_map do |coordination_task|
            if coordination_task.respond_to?(:action)
                expand_coordination_models(coordination_task.action)
            end
        end.compact
    else
        [action]
    end
end

#is_self_contained(action_or_profile = subject_syskit_model, options = Hash.new) ⇒ Object

Spec-style call for #assert_is_self_contained

Examples:

verify that all definitions of a profile are self-contained

describe MyBundle::Profiles::MyProfile do
  it { is_self_contained }
end


130
131
132
# File 'lib/syskit/test/profile_assertions.rb', line 130

def is_self_contained(action_or_profile = subject_syskit_model, options = Hash.new)
    assert_is_self_contained(action_or_profile, options)
end