diff --git a/.rubocop.yml b/.rubocop.yml index ca805939a..bc5d530d3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -54,7 +54,7 @@ Metrics/ModuleLength: - '**/test/**/*_test.rb' Metrics/BlockLength: - ExcludedMethods: + AllowedMethods: - describe - it diff --git a/Rakefile b/Rakefile index d17269a28..4be210dbf 100644 --- a/Rakefile +++ b/Rakefile @@ -57,6 +57,10 @@ Rake::TestTask.new("test:core") do |t| .exclude("test/app/test_run.rb") .exclude("test/interface/async/test_interface.rb") end + test_files = + test_files + .exclude("test/interface/v1/**/*") + .exclude("test/interface/v2/**/*") test_files = test_files.exclude("test/test_gui.rb") unless has_gui t.test_files = test_files t.warning = false @@ -79,6 +83,7 @@ Rake::TestTask.new("test:interface:v2") do |t| end task "test" => "test:core" +task "test" => "test:interface:v1" unless RUBY_VERSION >= "3.0" task "test" => "test:interface:v2" task "rubocop" do diff --git a/bin/roby-display b/bin/roby-display index 207eac4ca..c3d7d4235 100755 --- a/bin/roby-display +++ b/bin/roby-display @@ -6,6 +6,7 @@ begin Roby::CLI::Display.start(ARGV) exit 0 rescue Interrupt + require "roby" Roby.info "Interrupted by user" exit 1 rescue Exception => e diff --git a/lib/roby/actions/models/interface_base.rb b/lib/roby/actions/models/interface_base.rb index 4037889a9..843c52bfd 100644 --- a/lib/roby/actions/models/interface_base.rb +++ b/lib/roby/actions/models/interface_base.rb @@ -373,7 +373,7 @@ def method_missing(name, *args, **kw) # Declare that this fault response table should be used on all plans # that are going to use this action interface - def use_fault_response_table(table_model, arguments = {}) + def use_fault_response_table(table_model, **arguments) table_model.validate_arguments(arguments) fault_response_tables << [table_model, arguments] end diff --git a/lib/roby/app.rb b/lib/roby/app.rb index a8732b6ab..97efcb8f4 100644 --- a/lib/roby/app.rb +++ b/lib/roby/app.rb @@ -1100,7 +1100,7 @@ def setup self.planners.each do |planner| if planner.respond_to?(:each_fault_response_table) planner.each_fault_response_table do |table, arguments| - plan.use_fault_response_table table, arguments + plan.use_fault_response_table table, **arguments end end end @@ -1988,7 +1988,7 @@ def test_files_for(model) test_files = [] model.definition_location.each do |location| - file = location.absolute_path + next unless (file = location.absolute_path) next unless (base_path = find_base_path_for(file)) relative = Pathname.new(file).relative_path_from(base_path) diff --git a/lib/roby/app/cucumber/controller.rb b/lib/roby/app/cucumber/controller.rb index d75648198..b2c395db3 100644 --- a/lib/roby/app/cucumber/controller.rb +++ b/lib/roby/app/cucumber/controller.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "roby/interface/v1/async" - module Roby module App module Cucumber @@ -25,6 +23,9 @@ class InvalidState < RuntimeError; end # Actions that would be started by {#current_batch} attr_reader :pending_actions + # The remote interface version to use + attr_accessor :interface_version + # Whether the process should abort when an error is detected, or # keep running the actions as-is. The latter is useful for # debugging @@ -50,21 +51,52 @@ def roby_connected? @roby_interface&.connected? end + def self.roby_default_interface_version + if (v = ENV["ROBY_DEFAULT_INTERFACE_VERSION"]) + Integer(v) + elsif RUBY_VERSION >= "3.0" + 2 + else + 1 + end + end + + def self.roby_default_interface_port(version) + roby_interface_module(version)::DEFAULT_PORT + end + + def self.roby_interface_module(version) + if version == 1 + Roby::Interface::V1 + else + Roby::Interface::V2 + end + end + # @param [Integer] port the port through which we should connect # to the Roby interface. Set to zero to pick a random port. def initialize( - port: Roby::Interface::DEFAULT_PORT, keep_running: (ENV["CUCUMBER_KEEP_RUNNING"] == "1"), - validation_mode: (ENV["ROBY_VALIDATE_STEPS"] == "1") + validation_mode: (ENV["ROBY_VALIDATE_STEPS"] == "1"), + interface_version: self.class.roby_default_interface_version, + port: self.class.roby_default_interface_port(interface_version) ) + require "roby/interface/v#{interface_version}/async" + @roby_pid = nil @roby_port = port @background_jobs = [] @keep_running = keep_running @validation_mode = validation_mode + @interface_version = interface_version + @port = port @pending_actions = [] end + def roby_interface_module + self.class.roby_interface_module(@interface_version) + end + # The object used to communicate with the Roby instance # # @return [Roby::Interface::V1::Async::Interface] @@ -76,7 +108,7 @@ def roby_interface end @roby_interface ||= - Roby::Interface::V1::Async::Interface + roby_interface_module::Async::Interface .new("localhost", port: @roby_port) end @@ -106,7 +138,8 @@ def roby_start( options << "--log-dir=#{log_dir}" if log_dir if @roby_port == 0 server = TCPServer.new("localhost", 0) - options << "--interface-fd=#{server.fileno}" + options << + "--interface-v#{@interface_version}-fd=#{server.fileno}" spawn_options = spawn_options.merge({ server => server }) @roby_port = server.local_address.ip_port else @@ -116,6 +149,7 @@ def roby_start( Gem.ruby, File.join(Roby::BIN_DIR, "roby"), "run", "--robot=#{robot_name},#{robot_type}", "--controller", + "--interface-versions=#{@interface_version}", "--quiet", *options, *state.map { |k, v| "--set=#{k}=#{v}" }, @@ -358,7 +392,7 @@ def __start_job(description, m, arguments, monitoring) return end - action = Interface::V1::Async::ActionMonitor.new( + action = roby_interface_module::Async::ActionMonitor.new( roby_interface, m, arguments ) action.restart(batch: current_batch) @@ -434,7 +468,7 @@ def run_job(m, arguments = {}) return end - action = Interface::V1::Async::ActionMonitor.new( + action = roby_interface_module::Async::ActionMonitor.new( roby_interface, m, arguments ) action.restart(batch: current_batch) diff --git a/lib/roby/app/debug.rb b/lib/roby/app/debug.rb index 2174c625f..6a9dbc03e 100644 --- a/lib/roby/app/debug.rb +++ b/lib/roby/app/debug.rb @@ -3,6 +3,7 @@ require "stackprof" require "rbtrace" require "objspace" +require "roby/interface/core" module Roby module App @@ -27,7 +28,7 @@ def stackprof_start(one_shot: false, cycles: nil, mode: :cpu, interval: nil, raw else 1000 end - StackProf.start(mode: mode, interval: interval, raw: raw) + StackProf.start({ mode: mode, interval: interval, raw: raw }) if one_shot && !cycles cycles = 1 @@ -48,7 +49,7 @@ def stackprof_start(one_shot: false, cycles: nil, mode: :cpu, interval: nil, raw execution_engine.remove_propagation_handler(@cycle_counter_handler) @cycle_counter_handler = nil else - StackProf.start(mode: mode, interval: interval) + StackProf.start({ mode: mode, interval: interval }) end end end diff --git a/lib/roby/app/rake.rb b/lib/roby/app/rake.rb index 2fefeb9ac..8628da73a 100644 --- a/lib/roby/app/rake.rb +++ b/lib/roby/app/rake.rb @@ -805,29 +805,43 @@ def self.define_rubocop_if_enabled( ) return false unless Rake.use_rubocop? - begin - require "rubocop/rake_task" - rescue LoadError - raise if required - - return + if detect_rubocop? + define_rubocop(junit: junit, report_dir: report_dir) + elsif required + raise "rubocop required but not present" end - define_rubocop(junit: junit, report_dir: report_dir) true end + def self.detect_rubocop? + # Do NOT use out: :close here, it breaks bundler in some ways + run_rubocop("--version", out: "/dev/null") + true + rescue Errno::ENOENT + false + end + def self.define_rubocop( junit: Rake.use_junit?, report_dir: Rake.report_dir ) - require "rubocop/rake_task" - RuboCop::RakeTask.new do |t| - if junit - t.formatters << "junit" - t.options << "-o" << "#{report_dir}/rubocop.junit.xml" - end + options = [] + if junit + options.concat( + ["-f", "junit", "--out", + File.join(report_dir, "#{report_dir}/rubocop.junit.xml")] + ) + end + + ::Rake::Task.define_task "rubocop" do + run_rubocop(*options) end end + + def self.run_rubocop(*arguments, **options) + system(ENV["RUBOCOP_CMD"] || "rubocop", *arguments, + exception: true, **options) + end end end end diff --git a/lib/roby/app/scripts/run.rb b/lib/roby/app/scripts/run.rb index 617216100..867bd8bb1 100644 --- a/lib/roby/app/scripts/run.rb +++ b/lib/roby/app/scripts/run.rb @@ -37,7 +37,11 @@ app.log_create_current = false end opt.on "--interface-fd=FD", Integer, - "file descriptor to use for the interface server" do |fd| + "deprecated, use --interface-v1-fd instead" do |fd| + app.shell_interface_fd = fd + end + opt.on "--interface-v1-fd=FD", Integer, + "file descriptor to use for the v1 interface server" do |fd| app.shell_interface_fd = fd end opt.on "--interface-v2-fd=FD", Integer, diff --git a/lib/roby/cli/gen/app/.rubocop-version b/lib/roby/cli/gen/app/.rubocop-version new file mode 100644 index 000000000..0936d60d4 --- /dev/null +++ b/lib/roby/cli/gen/app/.rubocop-version @@ -0,0 +1 @@ +1.64.1 diff --git a/lib/roby/cli/gen/app/.rubocop.yml b/lib/roby/cli/gen/app/.rubocop.yml index 32a18b0fd..9c9b85a8e 100644 --- a/lib/roby/cli/gen/app/.rubocop.yml +++ b/lib/roby/cli/gen/app/.rubocop.yml @@ -1,3 +1,6 @@ inherit_gem: rubocop-rock: defaults.yml +AllCops: + NewCops: enable + diff --git a/lib/roby/cli/gen/helpers.rb b/lib/roby/cli/gen/helpers.rb index 36d87df65..6e474834a 100644 --- a/lib/roby/cli/gen/helpers.rb +++ b/lib/roby/cli/gen/helpers.rb @@ -198,7 +198,7 @@ def in_module(*module_path) close_code = [] last_module_i = module_path.size - 1 module_path.each_with_index do |m, i| - nodoc = " #:nodoc:" if i == last_module_i + nodoc = " # :nodoc:" if i == last_module_i open_code.push "#{indent}module #{m}#{nodoc}" close_code.unshift "#{indent}end" indent += " " diff --git a/lib/roby/cli/gen/roby_app/config/robots/robot.rb.erb b/lib/roby/cli/gen/roby_app/config/robots/robot.rb.erb index f3387e7d8..065e6b7ab 100644 --- a/lib/roby/cli/gen/roby_app/config/robots/robot.rb.erb +++ b/lib/roby/cli/gen/roby_app/config/robots/robot.rb.erb @@ -1,7 +1,7 @@ # frozen_string_literal: true <% if robot_name != 'default' %>## A common pattern is to load the 'default' robot configuration -require_relative "./default" +require_relative "default" <% end %>## One can require the configuration from another robot, for instance if one has ## a common robot class with minor modifications @@ -9,7 +9,7 @@ require_relative "./default" # require 'config/robots/robot_class' # Block evaluated at the very beginning of the Roby app initialization -Robot.init do +Robot.init do # rubocop:disable Lint/EmptyBlock ## Make models from another Roby app accessible # Relative paths are resolved from the root of this app # Roby.app.register_app('../separate_path') @@ -17,17 +17,17 @@ end # Block evaluated to configure the system, that is set up values in Roby's Conf # and State -Robot.setup do +Robot.setup do # rubocop:disable Lint/EmptyBlock end # Block evaluated to load the models this robot requires # # This is called after `setup` -Robot.requires do +Robot.requires do # rubocop:disable Lint/EmptyBlock end # The opposite of 'setup' (and 'requires') -Robot.cleanup do +Robot.cleanup do # rubocop:disable Lint/EmptyBlock end # Setup of the robot's main action interface @@ -40,17 +40,17 @@ end # # use_profile <%= Roby.app.module_name %>::Profiles::BaseProfile # -Robot.actions do +Robot.actions do # rubocop:disable Lint/EmptyBlock end # Block evaluated when the Roby app is fully setup, and the robot ready to # start. This is where one usually adds permanent tasks and/or status lines -Robot.controller do +Robot.controller do # rubocop:disable Lint/EmptyBlock end # Block evaluated right after the execution, but before the cleanup # # In particular, this is executed at teardown between each tests. Mostly, undo # things here that the controller block would have registered. -Robot.shutdown do +Robot.shutdown do # rubocop:disable Lint/EmptyBlock end diff --git a/lib/roby/coordination/base.rb b/lib/roby/coordination/base.rb index aaf5fa169..54bc087b5 100644 --- a/lib/roby/coordination/base.rb +++ b/lib/roby/coordination/base.rb @@ -92,7 +92,7 @@ def attach_fault_response_tables_to(_task) val end end - root_task.use_fault_response_table(table, arguments) + root_task.use_fault_response_table(table, **arguments) end end diff --git a/lib/roby/coordination/models/action_state_machine.rb b/lib/roby/coordination/models/action_state_machine.rb index 428b99719..aa8912028 100644 --- a/lib/roby/coordination/models/action_state_machine.rb +++ b/lib/roby/coordination/models/action_state_machine.rb @@ -126,13 +126,7 @@ def capture(state, event = nil, &block) raise ArgumentError, "#{event} is not an event that is active in state #{state}" end - filter = - if block - lambda(&block) - else - ->(ev) { ev.context.first } - end - + filter = block || ->(ev) { ev.context.first } capture = Capture.new(filter) captures[capture] = [state, event] capture diff --git a/lib/roby/coordination/models/base.rb b/lib/roby/coordination/models/base.rb index 0c84ed71b..67d8510a0 100644 --- a/lib/roby/coordination/models/base.rb +++ b/lib/roby/coordination/models/base.rb @@ -182,7 +182,7 @@ def validate_event(object) # Declare that this fault response table should be active as long as # this coordination model is - def use_fault_response_table(table_model, arguments = {}) + def use_fault_response_table(table_model, **arguments) arguments = table_model.validate_arguments(arguments) used_fault_response_tables << [table_model, arguments] end diff --git a/lib/roby/droby/object_manager.rb b/lib/roby/droby/object_manager.rb index 78112e44d..749f5a402 100644 --- a/lib/roby/droby/object_manager.rb +++ b/lib/roby/droby/object_manager.rb @@ -142,7 +142,7 @@ def deregister_siblings(local_object, siblings) # This registers the mapping for the local process (local_id => # local_object.droby_id), along with known siblings if provided def register_object(local_object, known_siblings = {}) - register_siblings(local_object, local_id => local_object.droby_id) + register_siblings(local_object, { local_id => local_object.droby_id }) register_siblings(local_object, known_siblings) end diff --git a/lib/roby/interface/v1.rb b/lib/roby/interface/v1.rb index 3d2a20761..a42650098 100644 --- a/lib/roby/interface/v1.rb +++ b/lib/roby/interface/v1.rb @@ -7,6 +7,8 @@ module Interface # V1 of the remote Roby control protocol module V1 extend Logger::Hierarchy + + DEFAULT_PORT = Roby::Interface::DEFAULT_PORT end end end diff --git a/lib/roby/interface/v2.rb b/lib/roby/interface/v2.rb index f510a2c86..f37f69fd8 100644 --- a/lib/roby/interface/v2.rb +++ b/lib/roby/interface/v2.rb @@ -7,6 +7,8 @@ module Interface # V2 of the remote Roby control protocol module V2 extend Logger::Hierarchy + + DEFAULT_PORT = Roby::Interface::DEFAULT_PORT_V2 end end end diff --git a/lib/roby/interface/v2/protocol.rb b/lib/roby/interface/v2/protocol.rb index 730e4bcc9..4858d7ff2 100644 --- a/lib/roby/interface/v2/protocol.rb +++ b/lib/roby/interface/v2/protocol.rb @@ -64,11 +64,20 @@ def pretty_print(pp) end end + TaskModel = Struct.new( + :name, keyword_init: true + ) do + def pretty_print(pp) + pp.text name + end + end + Task = Struct.new( :id, :model, :state, :started_since, :arguments, keyword_init: true ) do def pretty_print(pp) - pp.text "#{model} #{state}" + model.pretty_print(pp) + pp.text " #{state}" if started_since pp.breakable pp.text "Started for: #{started_since}" @@ -225,13 +234,22 @@ def self.marshal_action_model(channel, action, planner_model: nil) def self.marshal_task(channel, task) Task.new( id: task.droby_id.id, - model: task.model.name, + model: marshal_task_model(channel, task.model), state: task.current_state, started_since: task.start_event.last&.time, arguments: marshal_task_arguments(channel, task.arguments) ) end + # Convert a {Roby::Models::Task} + # + # @param [Channel] channel + # @param [Roby::Task] task + # @return [TaskModel] + def self.marshal_task_model(_channel, task_model) + TaskModel.new(name: task_model.name) + end + # Convert a {Roby::TaskArguments} # # @param [Channel] channel diff --git a/lib/roby/models/task.rb b/lib/roby/models/task.rb index 1471124b8..975359ebe 100644 --- a/lib/roby/models/task.rb +++ b/lib/roby/models/task.rb @@ -14,7 +14,7 @@ def initialize(model, arguments) end def as_plan - @model.as_plan(@arguments) + @model.as_plan(**@arguments) end end diff --git a/lib/roby/plan.rb b/lib/roby/plan.rb index 406deeb5a..c4e88470f 100644 --- a/lib/roby/plan.rb +++ b/lib/roby/plan.rb @@ -1947,7 +1947,7 @@ def query_result_set(matcher) # {#remove_fault_response_table} # @return [void] # @see remove_fault_response_table - def use_fault_response_table(table_model, arguments = {}) + def use_fault_response_table(table_model, **arguments) table = table_model.new(self, arguments) table.attach_to(self) active_fault_response_tables << table diff --git a/lib/roby/task.rb b/lib/roby/task.rb index 8a0ae07cc..e23ae4c43 100644 --- a/lib/roby/task.rb +++ b/lib/roby/task.rb @@ -1265,12 +1265,12 @@ def do_poll(plan) # :nodoc: # Declares that this fault response table should be made active when # this task starts, and deactivated when it ends - def use_fault_response_table(table_model, arguments = {}) + def use_fault_response_table(table_model, **arguments) arguments = table_model.validate_arguments(arguments) table = nil execute do |task| - table = task.plan.use_fault_response_table(table_model, arguments) + table = task.plan.use_fault_response_table(table_model, **arguments) end stop_event.on do |event| plan.remove_fault_response_table(table) diff --git a/lib/roby/tasks/aggregator.rb b/lib/roby/tasks/aggregator.rb index 2f0ece1fb..5c4f5fce2 100644 --- a/lib/roby/tasks/aggregator.rb +++ b/lib/roby/tasks/aggregator.rb @@ -3,7 +3,7 @@ module Roby::Tasks # Base functionality for the Sequence and Parallel aggregators class TaskAggregator < Roby::Task - def initialize(arguments = {}) + def initialize(**arguments) @tasks = [] @name = nil super diff --git a/lib/roby/tasks/parallel.rb b/lib/roby/tasks/parallel.rb index 09e37764f..1a13ecfb4 100644 --- a/lib/roby/tasks/parallel.rb +++ b/lib/roby/tasks/parallel.rb @@ -8,7 +8,7 @@ def name attr_reader :children_success - def initialize(arguments = {}) + def initialize(**arguments) super @children_success = Roby::AndGenerator.new diff --git a/lib/roby/transaction.rb b/lib/roby/transaction.rb index b1705e0f1..07ef43bc9 100644 --- a/lib/roby/transaction.rb +++ b/lib/roby/transaction.rb @@ -819,7 +819,7 @@ def apply_modifications_to_plan new_permanent_events.each { |ev| plan.add_permanent_event(ev) } active_fault_response_tables.each do |tbl| - plan.use_fault_response_table tbl.model, tbl.arguments + plan.use_fault_response_table tbl.model, **tbl.arguments end unmarked_permanent_events.each { |t| plan.unmark_permanent_event(t) } diff --git a/manifest.xml b/manifest.xml index 7ec98d140..633ec3ffd 100644 --- a/manifest.xml +++ b/manifest.xml @@ -47,5 +47,6 @@ + diff --git a/test/actions/models/test_interface.rb b/test/actions/models/test_interface.rb index 3a618f091..ba61ed888 100644 --- a/test/actions/models/test_interface.rb +++ b/test/actions/models/test_interface.rb @@ -75,14 +75,14 @@ def define_action(&block) interface_m.send(:define_method, :an_action, &block) end - def expect_arguments(args) + def expect_arguments(**args) flexmock(interface_m).new_instances - .should_receive(:an_action).with(args).pass_thru.once + .should_receive(:an_action).with(**args).pass_thru.once end it "sets up default arguments" do action_m.optional_arg("test", nil, 10) - define_action { |args = {}| self.class::AnAction.new } + define_action { |test:| self.class::AnAction.new } expect_arguments test: 10 interface_m.an_action.instanciate(plan) end @@ -123,14 +123,14 @@ def expect_arguments(args) it "allows to override default arguments" do action_m.optional_arg("test", nil, 10) - define_action { |args = {}| self.class::AnAction.new } + define_action { |test:| self.class::AnAction.new } expect_arguments test: 20 interface_m.an_action.instanciate(plan, test: 20) end it "raises ArgumentError if a required argument is not given" do action_m.required_arg("test", nil) - define_action { |args| } + define_action { |**args| } assert_raises(ArgumentError) do interface_m.an_action.instanciate(plan) end diff --git a/test/actions/models/test_method_action.rb b/test/actions/models/test_method_action.rb index 9d069adbc..fac90ef92 100644 --- a/test/actions/models/test_method_action.rb +++ b/test/actions/models/test_method_action.rb @@ -212,7 +212,7 @@ module Models it "registers the return type model even if the action already exists" do droby_remote = droby_to_remote(@action_m) flexmock(droby_remote_marshaller).should_receive(:local_object) - .with(droby_remote.returned_type, any).once + .with(droby_remote.returned_type).with_any_kw_args.once .pass_thru flexmock(droby_remote_marshaller).should_receive(:local_object) .pass_thru diff --git a/test/app/cucumber/test_controller.rb b/test/app/cucumber/test_controller.rb index 0051f9a3c..7fb5283f4 100644 --- a/test/app/cucumber/test_controller.rb +++ b/test/app/cucumber/test_controller.rb @@ -250,11 +250,11 @@ class CucumberTestActions < Roby::Actions::Interface optional_arg('task_success', 'whether the action\\'s task should success after startup'). optional_arg('arg', 'the task argument'). returns(CucumberTestTask) - def cucumber_monitoring(arguments = Hash.new) + def cucumber_monitoring(**arguments) if arguments.delete(:fail) raise "failing the action" end - CucumberTestTask.new(arguments) + CucumberTestTask.new(**arguments) end describe('the test action'). @@ -263,8 +263,8 @@ def cucumber_monitoring(arguments = Hash.new) optional_arg('task_success', 'whether the action\\'s task should success after startup'). optional_arg('arg', 'the task argument'). returns(CucumberTestTask) - def cucumber_action(arguments = Hash.new) - CucumberTestTask.new(arguments) + def cucumber_action(**arguments) + CucumberTestTask.new(**arguments) end describe('a test action with required argument'). @@ -308,7 +308,7 @@ def poll_interface_until(timeout: 10) jobs = controller.roby_interface.client.each_job.to_a assert_equal "CucumberTestTask", jobs.first.placeholder_task.model.name - assert_equal 10, jobs.first.placeholder_task.arg + assert_equal 10, jobs.first.placeholder_task.arguments[:arg] end it "drops all main jobs after a run_job" do controller.start_job( @@ -320,7 +320,9 @@ def poll_interface_until(timeout: 10) ) controller.apply_current_batch jobs = controller.roby_interface.client.each_job.to_a - assert_equal([2], jobs.map { |t| t.placeholder_task.arg }) + + args = jobs.map { |t| t.placeholder_task.arguments[:arg] } + assert_equal [2], args end it "does allow to queue new jobs again after a run_job" do controller.start_job( @@ -335,8 +337,10 @@ def poll_interface_until(timeout: 10) ) controller.apply_current_batch jobs = controller.roby_interface.client.each_job.to_a - assert_equal [2, 3], - jobs.map { |t| t.placeholder_task.arg }.sort + assert_equal( + [2, 3], + jobs.map { |t| t.placeholder_task.arguments[:arg] }.sort + ) end it "passes arguments to the action" do controller.start_job( @@ -344,7 +348,7 @@ def poll_interface_until(timeout: 10) ) controller.apply_current_batch jobs = controller.roby_interface.client.each_job.to_a - assert_equal 20, jobs.first.placeholder_task.arg + assert_equal 20, jobs.first.placeholder_task.arguments[:arg] end it "registers the job as a main job" do job = controller.start_job( @@ -385,7 +389,7 @@ def poll_interface_until(timeout: 10) jobs = controller.roby_interface.client.each_job.to_a assert_equal "CucumberTestTask", jobs.first.placeholder_task.model.name - assert_equal 10, jobs.first.placeholder_task.arg + assert_equal 10, jobs.first.placeholder_task.arguments[:arg] end it "passes arguments to the action" do controller.start_monitoring_job( @@ -393,7 +397,8 @@ def poll_interface_until(timeout: 10) ) controller.apply_current_batch jobs = controller.roby_interface.client.each_job.to_a - assert_equal Hash[arg: 20], jobs.first.task.action_arguments + assert_equal Hash[arg: 20], + jobs.first.task.arguments[:action_arguments] end it "registers the job as a monitoring job" do job = controller.start_monitoring_job( diff --git a/test/app/test_debug.rb b/test/app/test_debug.rb index a922141d4..3ce154556 100644 --- a/test/app/test_debug.rb +++ b/test/app/test_debug.rb @@ -34,12 +34,12 @@ def mock_context end it "passes the mode, interval and raw arguments to StackProf" do mode, interval, raw = flexmock, flexmock, flexmock - flexmock(StackProf).should_receive(:start).with(mode: mode, interval: interval, raw: raw).once + flexmock(StackProf).should_receive(:start).with({ mode: mode, interval: interval, raw: raw }).once debug.stackprof_start(mode: mode, interval: interval, raw: raw) end it "saves after the specified number of cycles" do mock_context do |debug, stackprof| - stackprof.should_receive(:start).once + stackprof.should_receive(:start).with_any_kw_args.once debug.stackprof_start(cycles: 5) end 2.times do @@ -57,7 +57,7 @@ def mock_context end it "stops and saves after the specified number of cycles if one_shot is set" do mock_context do |debug, stackprof| - stackprof.should_receive(:start).once + stackprof.should_receive(:start).with_any_kw_args.once debug.stackprof_start(one_shot: true, cycles: 5) end mock_context do |debug, stackprof| @@ -103,13 +103,13 @@ def mock_context describe "#stackprof_stop" do it "stops profiling" do - flexmock(StackProf).should_receive(:start).once + flexmock(StackProf).should_receive(:start).with_any_kw_args.once flexmock(StackProf).should_receive(:stop).once debug.stackprof_start debug.stackprof_stop end it "disables the one_shot handler" do - flexmock(StackProf).should_receive(:start).once + flexmock(StackProf).should_receive(:start).with_any_kw_args.once flexmock(StackProf).should_receive(:stop).once debug.stackprof_start(one_shot: true) debug.stackprof_stop diff --git a/test/app/test_run.rb b/test/app/test_run.rb index 96f412b01..36a831747 100644 --- a/test/app/test_run.rb +++ b/test/app/test_run.rb @@ -10,7 +10,14 @@ module Roby describe "run" do include Test::ArubaMinitest - (1..2).each do |interface_version| + interface_versions = + if RUBY_VERSION >= "3.0" + [2] + else + [1, 2] + end + + interface_versions.each do |interface_version| before do @roby_app_interface_version = interface_version end diff --git a/test/coordination/test_action_state_machine.rb b/test/coordination/test_action_state_machine.rb index d9acf694f..a8c40af9e 100644 --- a/test/coordination/test_action_state_machine.rb +++ b/test/coordination/test_action_state_machine.rb @@ -14,7 +14,7 @@ module Coordination description = nil @action_m = Roby::Actions::Interface.new_submodel do describe("the start task").returns(task_m).optional_arg(:id, "the task ID") - define_method(:start_task) { |arg| task_m.new(id: arg[:id] || :start) } + define_method(:start_task) { |id: nil| task_m.new(id: id || :start) } describe("the next task").returns(task_m) define_method(:next_task) { task_m.new(id: :next) } describe("a monitoring task").returns(task_m) @@ -24,8 +24,8 @@ module Coordination @description = description end - def start_machine(action, *args) - task = action.instanciate(plan, *args) + def start_machine(action, **args) + task = action.instanciate(plan, **args) plan.add_permanent_task(task) execute { task.start! } task @@ -538,8 +538,8 @@ def state_machine(&block) child_task_m = task_m.new_submodel(name: "TaskChildModel") child_m = action_m.new_submodel do - define_method(:start_task) do |arg| - child_task_m.new(id: arg[:id] || :start) + define_method(:start_task) do |id: nil| + child_task_m.new(id: id || :start) end end state_machine("test") do diff --git a/test/droby/test_marshal.rb b/test/droby/test_marshal.rb index 26d57d1f7..2ce70c0a5 100644 --- a/test/droby/test_marshal.rb +++ b/test/droby/test_marshal.rb @@ -86,7 +86,7 @@ def droby_dump(peer) flexmock(object_manager, :strict).should_receive(:find_by_id) .with(remote_id, remote_object_id).and_return(obj = flexmock) flexmock(object_manager, :strict).should_receive(:register_siblings) - .once.with(obj, remote_id => remote_object_id) + .once.with(obj, { remote_id => remote_object_id }) assert_equal [true, obj], subject.find_local_object(marshalled) end diff --git a/test/droby/test_object_manager.rb b/test/droby/test_object_manager.rb index 51d65391e..0b2224832 100644 --- a/test/droby/test_object_manager.rb +++ b/test/droby/test_object_manager.rb @@ -53,7 +53,7 @@ module DRoby it "registers the siblings given as well as the local object's ID" do droby_id, siblings = flexmock, flexmock local_object = flexmock(droby_id: droby_id) - flexmock(subject).should_receive(:register_siblings).with(local_object, local_id => droby_id).once + flexmock(subject).should_receive(:register_siblings).with(local_object, { local_id => droby_id }).once flexmock(subject).should_receive(:register_siblings).with(local_object, siblings).once subject.register_object(local_object, siblings) end diff --git a/test/droby/v5/test_droby_dump.rb b/test/droby/v5/test_droby_dump.rb index 730afe4f9..64213587f 100644 --- a/test/droby/v5/test_droby_dump.rb +++ b/test/droby/v5/test_droby_dump.rb @@ -645,7 +645,7 @@ def an_action(arguments = {}); end matcher.with_child(task_m, Roby::TaskStructure::Dependency, flexmock(droby_dump: 42)) flexmock(demarshaller).should_receive(:local_object).with(42).and_return({}).once - flexmock(demarshaller).should_receive(:local_object).with(any, any).pass_thru + flexmock(demarshaller).should_receive(:local_object).with(any).with_any_kw_args.pass_thru matcher = transfer(self.matcher) edges = matcher.children.fetch(Roby::TaskStructure::Dependency) @@ -658,7 +658,7 @@ def an_action(arguments = {}); end matcher.with_parent(task_m, Roby::TaskStructure::Dependency, flexmock(droby_dump: 42)) flexmock(demarshaller).should_receive(:local_object).with(42).and_return({}).once - flexmock(demarshaller).should_receive(:local_object).with(any, any).pass_thru + flexmock(demarshaller).should_receive(:local_object).with(any).with_any_kw_args.pass_thru matcher = transfer(self.matcher) edges = matcher.parents.fetch(Roby::TaskStructure::Dependency) diff --git a/test/interface/v2/test_channel.rb b/test/interface/v2/test_channel.rb index 58c698414..d916f4956 100644 --- a/test/interface/v2/test_channel.rb +++ b/test/interface/v2/test_channel.rb @@ -38,9 +38,9 @@ module V2 @io_w.getsockopt(Socket::SOL_SOCKET, Socket::SO_RCVBUF).int @io_w.write("0" * io_w_buffer_size) # Just make sure ... - channel = Channel.new(@io_w, false) - assert_raises(Errno::EAGAIN) { @io_w.syswrite(" ") } + assert_raises(Errno::EAGAIN) { @io_w.write_nonblock(" ") } + channel = Channel.new(@io_w, false) channel.write_packet({}) end it "handles partial packets on write" do diff --git a/test/interface/v2/test_client.rb b/test/interface/v2/test_client.rb index c71515948..a537541fb 100644 --- a/test/interface/v2/test_client.rb +++ b/test/interface/v2/test_client.rb @@ -109,7 +109,7 @@ def while_polling_server interface.should_receive(actions: [stub_action("Test")]) interface .should_receive(:start_job) - .with("Test", { arg0: 10 }).once + .with("Test", arg0: 10).once .and_return(10) result = connect { |client| client.Test!(arg0: 10) } assert_equal 10, result diff --git a/test/test_app.rb b/test/test_app.rb index fb523e2ae..d95a064fe 100644 --- a/test/test_app.rb +++ b/test/test_app.rb @@ -316,17 +316,15 @@ def robots_dir end it "passes arguments to the action" do - arguments = { id: 10 } - task_t = Roby::Task.new_submodel task, planner_task = task_t.new, task_t.new task.planned_by planner_task planner = flexmock planning_method = flexmock - planning_method.should_receive(:plan_pattern).with(arguments).once.and_return(task) + planning_method.should_receive(:plan_pattern).with(id: 10).once.and_return(task) flexmock(app).should_receive(:action_from_model).with(task_t).and_return([planner, planning_method]) - assert_equal [task, planner_task], app.prepare_action(task_t, **arguments) + assert_equal [task, planner_task], app.prepare_action(task_t, id: 10) assert_same app.plan, task.plan end end diff --git a/test/test_event_generator.rb b/test/test_event_generator.rb index 40cd85b72..b71591db3 100644 --- a/test/test_event_generator.rb +++ b/test/test_event_generator.rb @@ -910,7 +910,7 @@ module Roby before do @command_hook = flexmock command_hook.should_receive(:call).by_default - plan.add(@generator = Roby::EventGenerator.new { command_hook.call }) + plan.add(@generator = Roby::EventGenerator.new { |*| command_hook.call }) flexmock(generator) flexmock(execution_engine) end @@ -964,9 +964,9 @@ module Roby describe "the command raises before the emission" do it "does not itself remove pending" do command_hook.should_receive(:call).and_raise(RuntimeError) - generator.should_receive(:emit_failed).once.and_return do |*args| + generator.should_receive(:emit_failed).once.and_return do |*args, **kw| assert generator.pending? - flexmock_invoke_original(generator, :emit_failed, *args) + generator.invoke_original(:emit_failed, *args, **kw) end expect_execution { generator.call } .to { have_error_matching CommandFailed } diff --git a/test/test_plan_object.rb b/test/test_plan_object.rb index c98e43563..ad453f525 100644 --- a/test/test_plan_object.rb +++ b/test/test_plan_object.rb @@ -117,10 +117,11 @@ module Roby describe "#promise" do it "creates a promise using the object's own executor" do plan.add(object = Task.new) - flexmock(Promise).should_receive(:new) - .with(execution_engine, - ->(h) { h[:executor].equal?(object.promise_executor) && h[:description] == "promise description" }, - Proc).once.and_return(promise = flexmock) + flexmock(Promise) + .should_receive(:new) + .with(execution_engine, Proc) + .with_kw_args(executor: object.promise_executor, description: "promise description") + .once.and_return(promise = flexmock) assert_equal promise, object.promise(description: "promise description") {} end end diff --git a/test/test_task.rb b/test/test_task.rb index a8d6b1d8a..319b86f65 100644 --- a/test/test_task.rb +++ b/test/test_task.rb @@ -1539,7 +1539,8 @@ def self.nominal_behaviour(context) end it "creates a promise using the serialized task executor otherwise" do flexmock(execution_engine).should_receive(:promise).once - .with(->(h) { h[:executor].equal?(task.promise_executor) }, Proc) + .with(Proc) + .with_kw_args(hsh(executor: task.promise_executor)) .and_return(ret = flexmock) assert_equal(ret, task.promise {}) end