module Syskit::Test::ProfileAssertions

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}

Public Instance Methods

Actions(arg) click to toggle source

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

@raise [ArgumentError] if the argument is invalid

# 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
AtomicActions(arg, &block) click to toggle source

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

# 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) click to toggle source

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

@param [Array,Action] arg the action that is expanded @param [Array<Roby::Actions::Action>] actions that

should be ignored. Actions are compared on the basis of their
model (arguments do not count)
# 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
assert_can_configure_together(*actions) click to toggle source

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}

# 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: []) click to toggle source

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

# 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) click to toggle source

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

It is stronger (and therefore includes) {assert_can_instanciate_together}

# 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: []) click to toggle source

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

# 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) click to toggle source

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)

# 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) click to toggle source

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.

# 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
can_configure_together(*actions) click to toggle source

Spec-style call for {#assert_can_configure_together}

# 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) click to toggle source

Spec-style call for {#assert_can_deploy}

@example verify that each definition of a profile can be deployed

describe MyBundle::Profiles::MyProfile do
  it { can_deploy }
end
# 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) click to toggle source

Spec-style call for {#assert_can_deploy_together}

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

describe MyBundle::Profiles::MyProfile do
  it { can_deploy_together }
end
# 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) click to toggle source

Spec-style call for {#assert_can_instanciate}

@example verify that all definitions of a profile can be instanciated

describe MyBundle::Profiles::MyProfile do
  it { can_instanciate }
end
# 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) click to toggle source

Spec-style call for {#assert_can_instanciate_together}

@example 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
# File lib/syskit/test/profile_assertions.rb, line 191
def can_instanciate_together(*actions)
    assert_can_instanciate_together(*actions)
end
expand_coordination_models(action) click to toggle source

@api private

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

# 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) click to toggle source

Spec-style call for {#assert_is_self_contained}

@example verify that all definitions of a profile are self-contained

describe MyBundle::Profiles::MyProfile do
  it { is_self_contained }
end
# 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