roby 0.8.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (644) hide show
  1. checksums.yaml +7 -0
  2. data/.deep-cover.rb +3 -0
  3. data/.gitattributes +1 -0
  4. data/.gitignore +24 -0
  5. data/.simplecov +10 -0
  6. data/.travis.yml +17 -0
  7. data/.yardopts +4 -0
  8. data/Gemfile +15 -0
  9. data/README.md +11 -0
  10. data/Rakefile +47 -177
  11. data/benchmark/{alloc_misc.rb → attic/alloc_misc.rb} +2 -2
  12. data/benchmark/{discovery_latency.rb → attic/discovery_latency.rb} +19 -19
  13. data/benchmark/{garbage_collection.rb → attic/garbage_collection.rb} +9 -9
  14. data/benchmark/{genom.rb → attic/genom.rb} +0 -0
  15. data/benchmark/attic/transactions.rb +62 -0
  16. data/benchmark/plan_basic_operations.rb +28 -0
  17. data/benchmark/relations/graph.rb +63 -0
  18. data/benchmark/ruby/identity.rb +18 -0
  19. data/benchmark/ruby/set_intersect_vs_hash_merge.rb +39 -0
  20. data/benchmark/ruby/yield_vs_block.rb +35 -0
  21. data/benchmark/run +5 -0
  22. data/benchmark/synthetic_plan_modifications_with_transactions.rb +79 -0
  23. data/benchmark/transactions.rb +99 -51
  24. data/bin/roby +38 -197
  25. data/bin/roby-display +14 -0
  26. data/bin/roby-log +3 -176
  27. data/doc/guide/{src → attic}/abstraction/achieve_with.page +1 -1
  28. data/doc/guide/{src → attic}/abstraction/forwarding.page +1 -1
  29. data/doc/guide/{src → attic}/abstraction/hierarchy.page +1 -1
  30. data/doc/guide/{src → attic}/abstraction/index.page +1 -1
  31. data/doc/guide/{src → attic}/abstraction/task_models.page +1 -1
  32. data/doc/guide/{overview.rdoc → attic/cycle/api_overview.rdoc} +6 -1
  33. data/doc/guide/{src → attic}/cycle/cycle-overview.png +0 -0
  34. data/doc/guide/{src → attic}/cycle/cycle-overview.svg +0 -0
  35. data/doc/guide/attic/cycle/error_handling.page +98 -0
  36. data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.png +0 -0
  37. data/doc/guide/{src → attic}/cycle/error_instantaneous_repair.svg +0 -0
  38. data/doc/guide/{src/cycle/error_handling.page → attic/cycle/error_sources.page} +46 -89
  39. data/doc/guide/{src → attic}/cycle/garbage_collection.page +1 -1
  40. data/doc/guide/{src → attic}/cycle/index.page +1 -1
  41. data/doc/guide/{src → attic}/cycle/propagation.page +11 -1
  42. data/doc/guide/{src → attic}/cycle/propagation_diamond.png +0 -0
  43. data/doc/guide/{src → attic}/cycle/propagation_diamond.svg +0 -0
  44. data/doc/guide/attic/plans/building_plans.page +89 -0
  45. data/doc/guide/attic/plans/code.page +192 -0
  46. data/doc/guide/{src/basics → attic/plans}/events.page +3 -4
  47. data/doc/guide/attic/plans/index.page +7 -0
  48. data/doc/guide/{plan_modifications.rdoc → attic/plans/plan_modifications.rdoc} +5 -3
  49. data/doc/guide/{src/basics → attic/plans}/plan_objects.page +2 -1
  50. data/doc/guide/attic/plans/querying_plans.page +5 -0
  51. data/doc/guide/{src/basics → attic/plans}/tasks.page +20 -20
  52. data/doc/guide/config.yaml +7 -4
  53. data/doc/guide/ext/extended_menu.rb +29 -0
  54. data/doc/guide/ext/init.rb +6 -0
  55. data/doc/guide/ext/rdoc_links.rb +7 -6
  56. data/doc/guide/src/advanced_concepts/history.page +5 -0
  57. data/doc/guide/src/advanced_concepts/index.page +11 -0
  58. data/doc/guide/src/advanced_concepts/recognizing_patterns.page +83 -0
  59. data/doc/guide/src/advanced_concepts/scheduling.page +87 -0
  60. data/doc/guide/src/advanced_concepts/transactions.page +5 -0
  61. data/doc/guide/src/advanced_concepts/unreachability.page +42 -0
  62. data/doc/guide/src/base.template +96 -0
  63. data/doc/guide/src/basics_shell_header.txt +5 -7
  64. data/doc/guide/src/building/action_coordination.page +96 -0
  65. data/doc/guide/src/building/actions.page +124 -0
  66. data/doc/guide/src/building/file_layout.page +71 -0
  67. data/doc/guide/src/building/index.page +50 -0
  68. data/doc/guide/src/building/patterns.page +86 -0
  69. data/doc/guide/src/building/patterns_forwarding.png +0 -0
  70. data/doc/guide/src/building/patterns_forwarding.svg +277 -0
  71. data/doc/guide/src/building/runtime.page +95 -0
  72. data/doc/guide/src/building/task_models.page +94 -0
  73. data/doc/guide/src/building/tasks.page +284 -0
  74. data/doc/guide/src/concepts/error_handling.page +100 -0
  75. data/doc/guide/src/concepts/exception_propagation.png +0 -0
  76. data/doc/guide/src/concepts/exception_propagation.svg +445 -0
  77. data/doc/guide/src/concepts/execution.page +85 -0
  78. data/doc/guide/src/concepts/execution.png +0 -0
  79. data/doc/guide/src/concepts/execution.svg +573 -0
  80. data/doc/guide/src/concepts/execution_cycle.png +0 -0
  81. data/doc/guide/src/concepts/garbage_collection.page +57 -0
  82. data/doc/guide/src/concepts/index.page +27 -0
  83. data/doc/guide/src/concepts/plans.page +101 -0
  84. data/doc/guide/src/concepts/policy.page +31 -0
  85. data/doc/guide/src/concepts/reactor.page +61 -0
  86. data/doc/guide/src/concepts/simple_plan_example.png +0 -0
  87. data/doc/guide/src/concepts/simple_plan_example.svg +376 -0
  88. data/doc/guide/src/default.template +9 -74
  89. data/doc/guide/src/event_relations/forward.page +71 -0
  90. data/doc/guide/src/event_relations/index.page +12 -0
  91. data/doc/guide/src/event_relations/scheduling_constraints.page +43 -0
  92. data/doc/guide/src/event_relations/signal.page +55 -0
  93. data/doc/guide/src/event_relations/temporal_constraints.page +77 -0
  94. data/doc/guide/src/htmldoc.metainfo +21 -8
  95. data/doc/guide/src/index.page +8 -3
  96. data/doc/guide/src/{introduction/install.page → installation/index.page} +37 -25
  97. data/doc/guide/src/installation/publications.page +14 -0
  98. data/doc/guide/src/{introduction → installation}/videos.page +14 -7
  99. data/doc/guide/src/interacting/index.page +16 -0
  100. data/doc/guide/src/interacting/run.page +33 -0
  101. data/doc/guide/src/interacting/shell.page +95 -0
  102. data/doc/guide/src/plugins/creating_plugins.page +72 -0
  103. data/doc/guide/src/plugins/index.page +27 -5
  104. data/doc/guide/src/plugins/{fault_tolerance.page → standard_plugins/fault_tolerance.page} +2 -2
  105. data/doc/guide/src/plugins/standard_plugins/index.page +11 -0
  106. data/doc/guide/src/plugins/{subsystems.page → standard_plugins/subsystems.page} +2 -2
  107. data/doc/guide/src/style_screen.css +687 -0
  108. data/doc/guide/src/task_relations/dependency.page +107 -0
  109. data/doc/guide/src/task_relations/executed_by.page +77 -0
  110. data/doc/guide/src/task_relations/index.page +12 -0
  111. data/doc/guide/src/task_relations/new_relations.page +119 -0
  112. data/doc/guide/src/task_relations/planned_by.page +46 -0
  113. data/doc/guide/src/tutorial/app.page +117 -0
  114. data/doc/guide/src/{basics → tutorial}/code_examples.page +6 -5
  115. data/doc/guide/src/{basics → tutorial}/dry.page +15 -15
  116. data/doc/guide/src/{basics → tutorial}/errors.page +43 -68
  117. data/doc/guide/src/tutorial/events.page +195 -0
  118. data/doc/guide/src/{basics → tutorial}/hierarchy.page +53 -52
  119. data/doc/guide/src/tutorial/index.page +13 -0
  120. data/doc/guide/src/tutorial/log_replay/goForward_1.png +0 -0
  121. data/doc/guide/src/tutorial/log_replay/goForward_2.png +0 -0
  122. data/doc/guide/src/tutorial/log_replay/goForward_3.png +0 -0
  123. data/doc/guide/src/{basics → tutorial}/log_replay/goForward_4.png +0 -0
  124. data/doc/guide/src/tutorial/log_replay/goForward_5.png +0 -0
  125. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_1.png +0 -0
  126. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_2.png +0 -0
  127. data/doc/guide/src/{basics → tutorial}/log_replay/hierarchy_error_3.png +0 -0
  128. data/doc/guide/src/tutorial/log_replay/moveto_code_error.png +0 -0
  129. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_1.png +0 -0
  130. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_2.png +0 -0
  131. data/doc/guide/src/{basics → tutorial}/log_replay/plan_repair_3.png +0 -0
  132. data/doc/guide/src/tutorial/log_replay/plan_repair_4.png +0 -0
  133. data/doc/guide/src/tutorial/log_replay/roby_log_main_window.png +0 -0
  134. data/doc/guide/src/{basics → tutorial}/log_replay/roby_log_relation_window.png +0 -0
  135. data/doc/guide/src/{basics → tutorial}/log_replay/roby_replay_event_representation.png +0 -0
  136. data/doc/guide/src/tutorial/relations_display.page +153 -0
  137. data/doc/guide/src/{basics → tutorial}/roby_cycle_overview.png +0 -0
  138. data/doc/guide/src/tutorial/shell.page +121 -0
  139. data/doc/guide/src/{basics → tutorial}/summary.page +1 -1
  140. data/doc/guide/src/tutorial/tasks.page +374 -0
  141. data/lib/roby.rb +102 -47
  142. data/lib/roby/actions.rb +17 -0
  143. data/lib/roby/actions/action.rb +80 -0
  144. data/lib/roby/actions/interface.rb +45 -0
  145. data/lib/roby/actions/library.rb +23 -0
  146. data/lib/roby/actions/models/action.rb +224 -0
  147. data/lib/roby/actions/models/coordination_action.rb +58 -0
  148. data/lib/roby/actions/models/interface.rb +22 -0
  149. data/lib/roby/actions/models/interface_base.rb +294 -0
  150. data/lib/roby/actions/models/library.rb +12 -0
  151. data/lib/roby/actions/models/method_action.rb +90 -0
  152. data/lib/roby/actions/task.rb +114 -0
  153. data/lib/roby/and_generator.rb +125 -0
  154. data/lib/roby/app.rb +2795 -829
  155. data/lib/roby/app/autotest_console_reporter.rb +138 -0
  156. data/lib/roby/app/base.rb +21 -0
  157. data/lib/roby/app/cucumber.rb +2 -0
  158. data/lib/roby/app/cucumber/controller.rb +439 -0
  159. data/lib/roby/app/cucumber/helpers.rb +280 -0
  160. data/lib/roby/app/cucumber/world.rb +32 -0
  161. data/lib/roby/app/debug.rb +136 -0
  162. data/lib/roby/app/gen.rb +2 -0
  163. data/lib/roby/app/rake.rb +178 -38
  164. data/lib/roby/app/robot_config.rb +9 -0
  165. data/lib/roby/app/robot_names.rb +115 -0
  166. data/lib/roby/app/run.rb +3 -2
  167. data/lib/roby/app/scripts.rb +72 -0
  168. data/lib/roby/app/scripts/autotest.rb +173 -0
  169. data/lib/roby/app/scripts/display.rb +2 -0
  170. data/lib/roby/app/scripts/restart.rb +52 -0
  171. data/lib/roby/app/scripts/results.rb +17 -8
  172. data/lib/roby/app/scripts/run.rb +155 -24
  173. data/lib/roby/app/scripts/shell.rb +147 -62
  174. data/lib/roby/app/scripts/test.rb +107 -22
  175. data/lib/roby/app/test_reporter.rb +74 -0
  176. data/lib/roby/app/test_server.rb +159 -0
  177. data/lib/roby/app/vagrant.rb +47 -0
  178. data/lib/roby/backports.rb +16 -0
  179. data/lib/roby/cli/display.rb +190 -0
  180. data/lib/roby/cli/exceptions.rb +17 -0
  181. data/lib/roby/cli/gen/actions/class.rb +5 -0
  182. data/lib/roby/cli/gen/actions/test.rb +6 -0
  183. data/lib/roby/cli/gen/app/.yardopts +6 -0
  184. data/lib/roby/cli/gen/app/README.md +28 -0
  185. data/lib/roby/cli/gen/app/Rakefile +15 -0
  186. data/{app → lib/roby/cli/gen/app}/config/app.yml +29 -39
  187. data/lib/roby/cli/gen/app/models/.gitattributes +1 -0
  188. data/{app → lib/roby/cli/gen/app/scripts}/controllers/.gitattributes +0 -0
  189. data/{app/data/.gitattributes → lib/roby/cli/gen/app/test/.gitignore} +0 -0
  190. data/lib/roby/cli/gen/class/class.rb +6 -0
  191. data/lib/roby/cli/gen/class/test.rb +7 -0
  192. data/lib/roby/cli/gen/helpers.rb +203 -0
  193. data/lib/roby/cli/gen/module/module.rb +5 -0
  194. data/lib/roby/cli/gen/module/test.rb +6 -0
  195. data/lib/roby/cli/gen/roby_app/config/init.rb +17 -0
  196. data/lib/roby/cli/gen/roby_app/config/robots/robot.rb +40 -0
  197. data/lib/roby/cli/gen/task/class.rb +44 -0
  198. data/lib/roby/cli/gen/task/test.rb +6 -0
  199. data/lib/roby/cli/gen_main.rb +120 -0
  200. data/lib/roby/cli/log.rb +276 -0
  201. data/lib/roby/cli/log/flamegraph.html +499 -0
  202. data/lib/roby/cli/log/flamegraph_renderer.rb +88 -0
  203. data/lib/roby/cli/main.rb +153 -0
  204. data/lib/roby/coordination.rb +60 -0
  205. data/lib/roby/coordination/action_script.rb +25 -0
  206. data/lib/roby/coordination/action_state_machine.rb +125 -0
  207. data/lib/roby/coordination/actions.rb +106 -0
  208. data/lib/roby/coordination/base.rb +145 -0
  209. data/lib/roby/coordination/calculus.rb +40 -0
  210. data/lib/roby/coordination/child.rb +28 -0
  211. data/lib/roby/coordination/event.rb +29 -0
  212. data/lib/roby/coordination/fault_handler.rb +25 -0
  213. data/lib/roby/coordination/fault_handling_task.rb +13 -0
  214. data/lib/roby/coordination/fault_response_table.rb +110 -0
  215. data/lib/roby/coordination/models/action_script.rb +64 -0
  216. data/lib/roby/coordination/models/action_state_machine.rb +224 -0
  217. data/lib/roby/coordination/models/actions.rb +191 -0
  218. data/lib/roby/coordination/models/arguments.rb +55 -0
  219. data/lib/roby/coordination/models/base.rb +176 -0
  220. data/lib/roby/coordination/models/capture.rb +86 -0
  221. data/lib/roby/coordination/models/child.rb +35 -0
  222. data/lib/roby/coordination/models/event.rb +41 -0
  223. data/lib/roby/coordination/models/exceptions.rb +42 -0
  224. data/lib/roby/coordination/models/fault_handler.rb +219 -0
  225. data/lib/roby/coordination/models/fault_response_table.rb +77 -0
  226. data/lib/roby/coordination/models/root.rb +22 -0
  227. data/lib/roby/coordination/models/script.rb +283 -0
  228. data/lib/roby/coordination/models/task.rb +184 -0
  229. data/lib/roby/coordination/models/task_from_action.rb +50 -0
  230. data/lib/roby/coordination/models/task_from_as_plan.rb +33 -0
  231. data/lib/roby/coordination/models/task_from_instanciation_object.rb +31 -0
  232. data/lib/roby/coordination/models/task_from_variable.rb +27 -0
  233. data/lib/roby/coordination/models/task_with_dependencies.rb +48 -0
  234. data/lib/roby/coordination/models/variable.rb +32 -0
  235. data/lib/roby/coordination/script.rb +200 -0
  236. data/lib/roby/coordination/script_instruction.rb +12 -0
  237. data/lib/roby/coordination/task.rb +45 -0
  238. data/lib/roby/coordination/task_base.rb +69 -0
  239. data/lib/roby/coordination/task_script.rb +293 -0
  240. data/lib/roby/coordination/task_state_machine.rb +308 -0
  241. data/lib/roby/decision_control.rb +33 -21
  242. data/lib/roby/distributed_object.rb +76 -0
  243. data/lib/roby/droby.rb +17 -0
  244. data/lib/roby/droby/droby_id.rb +6 -0
  245. data/lib/roby/droby/enable.rb +153 -0
  246. data/lib/roby/droby/event_logger.rb +189 -0
  247. data/lib/roby/droby/event_logging.rb +57 -0
  248. data/lib/roby/droby/exceptions.rb +14 -0
  249. data/lib/roby/droby/identifiable.rb +22 -0
  250. data/lib/roby/droby/logfile.rb +141 -0
  251. data/lib/roby/droby/logfile/client.rb +176 -0
  252. data/lib/roby/droby/logfile/file_format.md +97 -0
  253. data/lib/roby/droby/logfile/index.rb +117 -0
  254. data/lib/roby/droby/logfile/reader.rb +139 -0
  255. data/lib/roby/droby/logfile/server.rb +199 -0
  256. data/lib/roby/droby/logfile/writer.rb +114 -0
  257. data/lib/roby/droby/marshal.rb +264 -0
  258. data/lib/roby/droby/marshallable.rb +12 -0
  259. data/lib/roby/droby/null_event_logger.rb +25 -0
  260. data/lib/roby/droby/object_manager.rb +205 -0
  261. data/lib/roby/droby/peer_id.rb +6 -0
  262. data/lib/roby/droby/plan_rebuilder.rb +373 -0
  263. data/lib/roby/droby/rebuilt_plan.rb +160 -0
  264. data/lib/roby/droby/remote_droby_id.rb +6 -0
  265. data/lib/roby/droby/timepoints.rb +205 -0
  266. data/lib/roby/droby/timepoints_ctf.metadata.erb +101 -0
  267. data/lib/roby/droby/timepoints_ctf.rb +125 -0
  268. data/lib/roby/droby/v5.rb +14 -0
  269. data/lib/roby/droby/v5/builtin.rb +120 -0
  270. data/lib/roby/droby/v5/droby_class.rb +45 -0
  271. data/lib/roby/droby/v5/droby_constant.rb +81 -0
  272. data/lib/roby/droby/v5/droby_dump.rb +1026 -0
  273. data/lib/roby/droby/v5/droby_id.rb +44 -0
  274. data/lib/roby/droby/v5/droby_model.rb +82 -0
  275. data/lib/roby/droby/v5/peer_id.rb +10 -0
  276. data/lib/roby/droby/v5/remote_droby_id.rb +42 -0
  277. data/lib/roby/event.rb +79 -957
  278. data/lib/roby/event_constraints.rb +835 -0
  279. data/lib/roby/event_generator.rb +1047 -0
  280. data/lib/roby/event_structure/causal_link.rb +6 -0
  281. data/lib/roby/event_structure/forwarding.rb +6 -0
  282. data/lib/roby/event_structure/precedence.rb +7 -0
  283. data/lib/roby/event_structure/signal.rb +8 -0
  284. data/lib/roby/event_structure/temporal_constraints.rb +640 -0
  285. data/lib/roby/exceptions.rb +446 -152
  286. data/lib/roby/executable_plan.rb +549 -0
  287. data/lib/roby/execution_engine.rb +1997 -950
  288. data/lib/roby/filter_generator.rb +26 -0
  289. data/lib/roby/gui/chronicle_view.rb +225 -0
  290. data/lib/roby/gui/chronicle_widget.rb +925 -0
  291. data/lib/roby/gui/dot_id.rb +11 -0
  292. data/lib/roby/gui/exception_view.rb +44 -0
  293. data/lib/roby/gui/log_display.rb +273 -0
  294. data/lib/roby/gui/model_views.rb +2 -0
  295. data/lib/roby/gui/model_views/action_interface.rb +53 -0
  296. data/lib/roby/gui/model_views/task.rb +47 -0
  297. data/lib/roby/gui/model_views/task.rhtml +41 -0
  298. data/lib/roby/gui/object_info_view.rb +89 -0
  299. data/lib/roby/gui/plan_dot_layout.rb +427 -0
  300. data/lib/roby/gui/plan_rebuilder_widget.rb +357 -0
  301. data/lib/roby/gui/qt4_toMSecsSinceEpoch.rb +8 -0
  302. data/lib/roby/gui/relations_view.rb +278 -0
  303. data/lib/roby/gui/relations_view/relations.ui +139 -0
  304. data/lib/roby/gui/relations_view/relations_canvas.rb +1088 -0
  305. data/lib/roby/gui/relations_view/relations_config.rb +292 -0
  306. data/lib/roby/gui/relations_view/relations_view.ui +53 -0
  307. data/lib/roby/gui/scheduler_view.css +24 -0
  308. data/lib/roby/gui/scheduler_view.rb +46 -0
  309. data/lib/roby/gui/scheduler_view.rhtml +53 -0
  310. data/lib/roby/gui/stepping.rb +93 -0
  311. data/lib/roby/gui/stepping.ui +181 -0
  312. data/lib/roby/gui/styles.rb +81 -0
  313. data/lib/roby/gui/task_display_configuration.rb +42 -0
  314. data/lib/roby/gui/task_state_at.rb +38 -0
  315. data/lib/roby/hooks.rb +26 -0
  316. data/lib/roby/interface.rb +136 -469
  317. data/lib/roby/interface/async.rb +20 -0
  318. data/lib/roby/interface/async/action_monitor.rb +188 -0
  319. data/lib/roby/interface/async/interface.rb +498 -0
  320. data/lib/roby/interface/async/job_monitor.rb +213 -0
  321. data/lib/roby/interface/async/log.rb +238 -0
  322. data/lib/roby/interface/async/new_job_listener.rb +79 -0
  323. data/lib/roby/interface/async/ui_connector.rb +183 -0
  324. data/lib/roby/interface/client.rb +553 -0
  325. data/lib/roby/interface/command.rb +24 -0
  326. data/lib/roby/interface/command_argument.rb +16 -0
  327. data/lib/roby/interface/command_library.rb +92 -0
  328. data/lib/roby/interface/droby_channel.rb +174 -0
  329. data/lib/roby/interface/exceptions.rb +22 -0
  330. data/lib/roby/interface/interface.rb +655 -0
  331. data/lib/roby/interface/job.rb +47 -0
  332. data/lib/roby/interface/rest.rb +10 -0
  333. data/lib/roby/interface/rest/api.rb +29 -0
  334. data/lib/roby/interface/rest/helpers.rb +24 -0
  335. data/lib/roby/interface/rest/server.rb +212 -0
  336. data/lib/roby/interface/server.rb +154 -0
  337. data/lib/roby/interface/shell_client.rb +468 -0
  338. data/lib/roby/interface/shell_subcommand.rb +24 -0
  339. data/lib/roby/interface/subcommand_client.rb +35 -0
  340. data/lib/roby/interface/tcp.rb +168 -0
  341. data/lib/roby/models/arguments.rb +112 -0
  342. data/lib/roby/models/plan_object.rb +83 -0
  343. data/lib/roby/models/task.rb +835 -0
  344. data/lib/roby/models/task_event.rb +62 -0
  345. data/lib/roby/models/task_service.rb +78 -0
  346. data/lib/roby/or_generator.rb +88 -0
  347. data/lib/roby/plan.rb +1751 -864
  348. data/lib/roby/plan_object.rb +611 -0
  349. data/lib/roby/plan_service.rb +200 -0
  350. data/lib/roby/promise.rb +332 -0
  351. data/lib/roby/queries.rb +23 -0
  352. data/lib/roby/queries/and_matcher.rb +32 -0
  353. data/lib/roby/queries/any.rb +27 -0
  354. data/lib/roby/queries/code_error_matcher.rb +58 -0
  355. data/lib/roby/queries/event_generator_matcher.rb +9 -0
  356. data/lib/roby/queries/execution_exception_matcher.rb +165 -0
  357. data/lib/roby/queries/index.rb +165 -0
  358. data/lib/roby/queries/localized_error_matcher.rb +149 -0
  359. data/lib/roby/queries/matcher_base.rb +107 -0
  360. data/lib/roby/queries/none.rb +27 -0
  361. data/lib/roby/queries/not_matcher.rb +30 -0
  362. data/lib/roby/queries/op_matcher.rb +8 -0
  363. data/lib/roby/queries/or_matcher.rb +30 -0
  364. data/lib/roby/queries/plan_object_matcher.rb +363 -0
  365. data/lib/roby/queries/query.rb +188 -0
  366. data/lib/roby/queries/task_event_generator_matcher.rb +86 -0
  367. data/lib/roby/queries/task_matcher.rb +344 -0
  368. data/lib/roby/relations.rb +42 -678
  369. data/lib/roby/relations/bidirectional_directed_adjacency_graph.rb +492 -0
  370. data/lib/roby/relations/directed_relation_support.rb +268 -0
  371. data/lib/roby/relations/event_relation_graph.rb +19 -0
  372. data/lib/roby/relations/fork_merge_visitor.rb +154 -0
  373. data/lib/roby/relations/graph.rb +533 -0
  374. data/lib/roby/relations/models/directed_relation_support.rb +11 -0
  375. data/lib/roby/relations/models/graph.rb +75 -0
  376. data/lib/roby/relations/models/task_relation_graph.rb +18 -0
  377. data/lib/roby/relations/space.rb +380 -0
  378. data/lib/roby/relations/task_relation_graph.rb +20 -0
  379. data/lib/roby/robot.rb +85 -38
  380. data/lib/roby/schedulers/basic.rb +155 -25
  381. data/lib/roby/schedulers/null.rb +20 -0
  382. data/lib/roby/schedulers/reporting.rb +31 -0
  383. data/lib/roby/schedulers/state.rb +129 -0
  384. data/lib/roby/schedulers/temporal.rb +91 -0
  385. data/lib/roby/singletons.rb +87 -0
  386. data/lib/roby/standalone.rb +4 -2
  387. data/lib/roby/standard_errors.rb +405 -82
  388. data/lib/roby/state.rb +6 -3
  389. data/lib/roby/state/conf_model.rb +5 -0
  390. data/lib/roby/state/events.rb +181 -95
  391. data/lib/roby/state/goal_model.rb +77 -0
  392. data/lib/roby/state/open_struct.rb +591 -0
  393. data/lib/roby/state/open_struct_model.rb +68 -0
  394. data/lib/roby/state/pos.rb +45 -45
  395. data/lib/roby/state/shapes.rb +11 -11
  396. data/lib/roby/state/state_model.rb +303 -0
  397. data/lib/roby/state/task.rb +43 -0
  398. data/lib/roby/support.rb +88 -148
  399. data/lib/roby/task.rb +1361 -1750
  400. data/lib/roby/task_arguments.rb +428 -0
  401. data/lib/roby/task_event.rb +127 -0
  402. data/lib/roby/task_event_generator.rb +337 -0
  403. data/lib/roby/task_service.rb +6 -0
  404. data/lib/roby/task_structure/conflicts.rb +104 -0
  405. data/lib/roby/task_structure/dependency.rb +932 -0
  406. data/lib/roby/task_structure/error_handling.rb +118 -0
  407. data/lib/roby/task_structure/executed_by.rb +234 -0
  408. data/lib/roby/task_structure/planned_by.rb +90 -0
  409. data/lib/roby/tasks/aggregator.rb +37 -0
  410. data/lib/roby/tasks/external_process.rb +275 -0
  411. data/lib/roby/tasks/group.rb +27 -0
  412. data/lib/roby/tasks/null.rb +19 -0
  413. data/lib/roby/tasks/parallel.rb +43 -0
  414. data/lib/roby/tasks/sequence.rb +88 -0
  415. data/lib/roby/tasks/simple.rb +21 -0
  416. data/lib/roby/{thread_task.rb → tasks/thread.rb} +50 -24
  417. data/lib/roby/tasks/timeout.rb +17 -0
  418. data/lib/roby/tasks/virtual.rb +55 -0
  419. data/lib/roby/template_plan.rb +7 -0
  420. data/lib/roby/test/aruba_minitest.rb +74 -0
  421. data/lib/roby/test/assertion.rb +16 -0
  422. data/lib/roby/test/assertions.rb +490 -0
  423. data/lib/roby/test/common.rb +368 -591
  424. data/lib/roby/test/dsl.rb +149 -0
  425. data/lib/roby/test/error.rb +18 -0
  426. data/lib/roby/test/event_reporter.rb +83 -0
  427. data/lib/roby/test/execution_expectations.rb +1134 -0
  428. data/lib/roby/test/expect_execution.rb +151 -0
  429. data/lib/roby/test/minitest_helpers.rb +166 -0
  430. data/lib/roby/test/roby_app_helpers.rb +200 -0
  431. data/lib/roby/test/run_planners.rb +155 -0
  432. data/lib/roby/test/self.rb +112 -0
  433. data/lib/roby/test/spec.rb +198 -0
  434. data/lib/roby/test/tasks/empty_task.rb +4 -4
  435. data/lib/roby/test/tasks/goto.rb +28 -27
  436. data/lib/roby/test/teardown_plans.rb +100 -0
  437. data/lib/roby/test/testcase.rb +239 -307
  438. data/lib/roby/test/tools.rb +159 -155
  439. data/lib/roby/test/validate_state_machine.rb +75 -0
  440. data/lib/roby/transaction.rb +1125 -0
  441. data/lib/roby/transaction/event_generator_proxy.rb +63 -0
  442. data/lib/roby/transaction/plan_object_proxy.rb +99 -0
  443. data/lib/roby/transaction/plan_service_proxy.rb +43 -0
  444. data/lib/roby/transaction/proxying.rb +120 -0
  445. data/lib/roby/transaction/task_event_generator_proxy.rb +19 -0
  446. data/lib/roby/transaction/task_proxy.rb +135 -0
  447. data/lib/roby/until_generator.rb +30 -0
  448. data/lib/roby/version.rb +5 -0
  449. data/lib/roby/yard.rb +169 -0
  450. data/lib/yard-roby.rb +1 -0
  451. data/manifest.xml +32 -6
  452. data/roby.gemspec +59 -0
  453. metadata +788 -587
  454. data/Manifest.txt +0 -321
  455. data/NOTES +0 -4
  456. data/README.txt +0 -166
  457. data/TODO.txt +0 -146
  458. data/app/README.txt +0 -24
  459. data/app/Rakefile +0 -8
  460. data/app/config/ROBOT.rb +0 -5
  461. data/app/config/init.rb +0 -33
  462. data/app/config/roby.yml +0 -3
  463. data/app/controllers/ROBOT.rb +0 -2
  464. data/app/planners/ROBOT/main.rb +0 -6
  465. data/app/planners/main.rb +0 -5
  466. data/app/scripts/distributed +0 -3
  467. data/app/scripts/generate/bookmarks +0 -3
  468. data/app/scripts/replay +0 -3
  469. data/app/scripts/results +0 -3
  470. data/app/scripts/run +0 -3
  471. data/app/scripts/server +0 -3
  472. data/app/scripts/shell +0 -3
  473. data/app/scripts/test +0 -3
  474. data/app/tasks/.gitattributes +0 -0
  475. data/app/tasks/ROBOT/.gitattributes +0 -0
  476. data/bin/roby-shell +0 -25
  477. data/doc/guide/src/basics/app.page +0 -139
  478. data/doc/guide/src/basics/index.page +0 -11
  479. data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
  480. data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
  481. data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
  482. data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
  483. data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
  484. data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
  485. data/doc/guide/src/basics/relations_display.page +0 -203
  486. data/doc/guide/src/basics/shell.page +0 -102
  487. data/doc/guide/src/default.css +0 -319
  488. data/doc/guide/src/introduction/index.page +0 -29
  489. data/doc/guide/src/introduction/publications.page +0 -14
  490. data/doc/guide/src/relations/dependency.page +0 -89
  491. data/doc/guide/src/relations/index.page +0 -12
  492. data/ext/droby/dump.cc +0 -175
  493. data/ext/droby/extconf.rb +0 -3
  494. data/ext/graph/algorithm.cc +0 -746
  495. data/ext/graph/extconf.rb +0 -7
  496. data/ext/graph/graph.cc +0 -575
  497. data/ext/graph/graph.hh +0 -183
  498. data/ext/graph/iterator_sequence.hh +0 -102
  499. data/ext/graph/undirected_dfs.hh +0 -226
  500. data/ext/graph/undirected_graph.hh +0 -421
  501. data/lib/roby/app/scripts/generate/bookmarks.rb +0 -162
  502. data/lib/roby/app/scripts/replay.rb +0 -31
  503. data/lib/roby/app/scripts/server.rb +0 -18
  504. data/lib/roby/basic_object.rb +0 -151
  505. data/lib/roby/config.rb +0 -14
  506. data/lib/roby/distributed.rb +0 -36
  507. data/lib/roby/distributed/base.rb +0 -448
  508. data/lib/roby/distributed/communication.rb +0 -875
  509. data/lib/roby/distributed/connection_space.rb +0 -616
  510. data/lib/roby/distributed/distributed_object.rb +0 -206
  511. data/lib/roby/distributed/drb.rb +0 -62
  512. data/lib/roby/distributed/notifications.rb +0 -531
  513. data/lib/roby/distributed/peer.rb +0 -555
  514. data/lib/roby/distributed/protocol.rb +0 -529
  515. data/lib/roby/distributed/proxy.rb +0 -343
  516. data/lib/roby/distributed/subscription.rb +0 -311
  517. data/lib/roby/distributed/transaction.rb +0 -498
  518. data/lib/roby/external_process_task.rb +0 -225
  519. data/lib/roby/graph.rb +0 -160
  520. data/lib/roby/log.rb +0 -3
  521. data/lib/roby/log/chronicle.rb +0 -303
  522. data/lib/roby/log/console.rb +0 -74
  523. data/lib/roby/log/data_stream.rb +0 -275
  524. data/lib/roby/log/dot.rb +0 -279
  525. data/lib/roby/log/event_stream.rb +0 -161
  526. data/lib/roby/log/file.rb +0 -396
  527. data/lib/roby/log/gui/basic_display.ui +0 -83
  528. data/lib/roby/log/gui/basic_display_ui.rb +0 -89
  529. data/lib/roby/log/gui/chronicle.rb +0 -26
  530. data/lib/roby/log/gui/chronicle_view.rb +0 -40
  531. data/lib/roby/log/gui/chronicle_view.ui +0 -70
  532. data/lib/roby/log/gui/chronicle_view_ui.rb +0 -90
  533. data/lib/roby/log/gui/data_displays.rb +0 -171
  534. data/lib/roby/log/gui/data_displays.ui +0 -155
  535. data/lib/roby/log/gui/data_displays_ui.rb +0 -146
  536. data/lib/roby/log/gui/notifications.rb +0 -26
  537. data/lib/roby/log/gui/relations.rb +0 -269
  538. data/lib/roby/log/gui/relations.ui +0 -123
  539. data/lib/roby/log/gui/relations_ui.rb +0 -120
  540. data/lib/roby/log/gui/relations_view.rb +0 -185
  541. data/lib/roby/log/gui/relations_view.ui +0 -149
  542. data/lib/roby/log/gui/relations_view_ui.rb +0 -144
  543. data/lib/roby/log/gui/replay.rb +0 -366
  544. data/lib/roby/log/gui/replay_controls.rb +0 -206
  545. data/lib/roby/log/gui/replay_controls.ui +0 -282
  546. data/lib/roby/log/gui/replay_controls_ui.rb +0 -249
  547. data/lib/roby/log/gui/runtime.rb +0 -130
  548. data/lib/roby/log/hooks.rb +0 -186
  549. data/lib/roby/log/logger.rb +0 -203
  550. data/lib/roby/log/notifications.rb +0 -244
  551. data/lib/roby/log/plan_rebuilder.rb +0 -468
  552. data/lib/roby/log/relations.rb +0 -1084
  553. data/lib/roby/log/server.rb +0 -547
  554. data/lib/roby/log/sqlite.rb +0 -47
  555. data/lib/roby/log/timings.rb +0 -233
  556. data/lib/roby/plan-object.rb +0 -371
  557. data/lib/roby/planning.rb +0 -13
  558. data/lib/roby/planning/loops.rb +0 -309
  559. data/lib/roby/planning/model.rb +0 -1012
  560. data/lib/roby/planning/task.rb +0 -180
  561. data/lib/roby/query.rb +0 -655
  562. data/lib/roby/relations/conflicts.rb +0 -67
  563. data/lib/roby/relations/dependency.rb +0 -358
  564. data/lib/roby/relations/ensured.rb +0 -19
  565. data/lib/roby/relations/error_handling.rb +0 -22
  566. data/lib/roby/relations/events.rb +0 -7
  567. data/lib/roby/relations/executed_by.rb +0 -208
  568. data/lib/roby/relations/influence.rb +0 -10
  569. data/lib/roby/relations/planned_by.rb +0 -63
  570. data/lib/roby/state/information.rb +0 -55
  571. data/lib/roby/state/state.rb +0 -367
  572. data/lib/roby/task-operations.rb +0 -186
  573. data/lib/roby/task_index.rb +0 -80
  574. data/lib/roby/test/distributed.rb +0 -230
  575. data/lib/roby/test/tasks/simple_task.rb +0 -23
  576. data/lib/roby/transactions.rb +0 -507
  577. data/lib/roby/transactions/proxy.rb +0 -325
  578. data/plugins/fault_injection/History.txt +0 -4
  579. data/plugins/fault_injection/README.txt +0 -34
  580. data/plugins/fault_injection/Rakefile +0 -12
  581. data/plugins/fault_injection/TODO.txt +0 -0
  582. data/plugins/fault_injection/app.rb +0 -52
  583. data/plugins/fault_injection/fault_injection.rb +0 -89
  584. data/plugins/fault_injection/test/test_fault_injection.rb +0 -78
  585. data/plugins/subsystems/README.txt +0 -37
  586. data/plugins/subsystems/Rakefile +0 -13
  587. data/plugins/subsystems/app.rb +0 -182
  588. data/plugins/subsystems/test/app/README +0 -24
  589. data/plugins/subsystems/test/app/Rakefile +0 -8
  590. data/plugins/subsystems/test/app/config/app.yml +0 -71
  591. data/plugins/subsystems/test/app/config/init.rb +0 -12
  592. data/plugins/subsystems/test/app/config/roby.yml +0 -3
  593. data/plugins/subsystems/test/app/planners/main.rb +0 -20
  594. data/plugins/subsystems/test/app/scripts/distributed +0 -3
  595. data/plugins/subsystems/test/app/scripts/replay +0 -3
  596. data/plugins/subsystems/test/app/scripts/results +0 -3
  597. data/plugins/subsystems/test/app/scripts/run +0 -3
  598. data/plugins/subsystems/test/app/scripts/server +0 -3
  599. data/plugins/subsystems/test/app/scripts/shell +0 -3
  600. data/plugins/subsystems/test/app/scripts/test +0 -3
  601. data/plugins/subsystems/test/app/tasks/services.rb +0 -15
  602. data/plugins/subsystems/test/test_subsystems.rb +0 -78
  603. data/test/distributed/test_communication.rb +0 -195
  604. data/test/distributed/test_connection.rb +0 -284
  605. data/test/distributed/test_execution.rb +0 -378
  606. data/test/distributed/test_mixed_plan.rb +0 -341
  607. data/test/distributed/test_plan_notifications.rb +0 -238
  608. data/test/distributed/test_protocol.rb +0 -525
  609. data/test/distributed/test_query.rb +0 -106
  610. data/test/distributed/test_remote_plan.rb +0 -491
  611. data/test/distributed/test_transaction.rb +0 -466
  612. data/test/mockups/external_process +0 -28
  613. data/test/mockups/tasks.rb +0 -27
  614. data/test/planning/test_loops.rb +0 -432
  615. data/test/planning/test_model.rb +0 -427
  616. data/test/planning/test_task.rb +0 -126
  617. data/test/relations/test_conflicts.rb +0 -42
  618. data/test/relations/test_dependency.rb +0 -324
  619. data/test/relations/test_ensured.rb +0 -38
  620. data/test/relations/test_executed_by.rb +0 -224
  621. data/test/relations/test_planned_by.rb +0 -56
  622. data/test/suite_core.rb +0 -29
  623. data/test/suite_distributed.rb +0 -10
  624. data/test/suite_planning.rb +0 -4
  625. data/test/suite_relations.rb +0 -8
  626. data/test/tasks/test_external_process.rb +0 -126
  627. data/test/tasks/test_thread_task.rb +0 -70
  628. data/test/test_bgl.rb +0 -528
  629. data/test/test_event.rb +0 -969
  630. data/test/test_exceptions.rb +0 -591
  631. data/test/test_execution_engine.rb +0 -987
  632. data/test/test_gui.rb +0 -20
  633. data/test/test_interface.rb +0 -43
  634. data/test/test_log.rb +0 -125
  635. data/test/test_log_server.rb +0 -133
  636. data/test/test_plan.rb +0 -418
  637. data/test/test_query.rb +0 -424
  638. data/test/test_relations.rb +0 -260
  639. data/test/test_state.rb +0 -432
  640. data/test/test_support.rb +0 -16
  641. data/test/test_task.rb +0 -1181
  642. data/test/test_testcase.rb +0 -138
  643. data/test/test_transactions.rb +0 -610
  644. data/test/test_transactions_proxy.rb +0 -216
@@ -0,0 +1,138 @@
1
+ module Roby
2
+ module App
3
+ # Reporter class for the Roby autotest, that outputs on an IO object
4
+ class AutotestConsoleReporter
5
+ # @return [#puts] the IO on which reporting should be done
6
+ attr_reader :io
7
+
8
+ # @return [App::TestServer] the test server
9
+ attr_reader :server
10
+
11
+ # @return [Autorespawn::Manager] the autorespawn slave manager
12
+ attr_reader :manager
13
+
14
+ # @return [Hash<Autorespawn::Slave,Integer>] mapping from
15
+ # a slave to the unique ID associated with it
16
+ attr_reader :slave_to_id
17
+
18
+ # @return [Hash<Integer,Autorespawn::Slave>] mapping from
19
+ # a process ID to the slave object
20
+ attr_reader :pid_to_slave
21
+
22
+ # @api private
23
+ #
24
+ # Converts a slave object to the string displayed to the user
25
+ def slave_to_s(slave)
26
+ slave.name.sort_by(&:first).map { |k, v| "#{k}: #{v}" }
27
+ end
28
+
29
+ # @api private
30
+ #
31
+ # Register a new slave
32
+ #
33
+ # @return [Integer] the unique slave ID
34
+ def register_slave(slave)
35
+ if slave_to_id[slave]
36
+ raise ArgumentError, "#{slave} is already registered"
37
+ end
38
+ slave_to_id[slave] = (@slave_id += 1)
39
+ end
40
+
41
+ # @api private
42
+ #
43
+ # Register a new slave-to-PID mapping
44
+ #
45
+ # @param [Autorespawn::Slave] slave a slave whose #pid is valid
46
+ # @return [Integer] the slave's unique slave ID
47
+ # @raise [ArgumentError] if the slave has not been registered with
48
+ # {#register_slave} first
49
+ def register_slave_pid(slave)
50
+ if slave_id = slave_to_id[slave]
51
+ pid_to_slave[slave.pid] = slave
52
+ return slave_id
53
+ else
54
+ raise ArgumentError, "#{slave} has not been registered with #register_slave"
55
+ end
56
+ end
57
+
58
+ # @api private
59
+ #
60
+ # Returns a slave from its PID
61
+ #
62
+ # @param [Integer] pid the PID
63
+ # @return [(Autorespawn::Slave,Integer)] the slave and its unique
64
+ # slave ID
65
+ # @raise [ArgumentError] if no slave is registered for this PID
66
+ def slave_from_pid(pid)
67
+ if slave = pid_to_slave[pid]
68
+ return slave, slave_to_id[slave]
69
+ else
70
+ raise ArgumentError, "no slave registered for PID #{pid}"
71
+ end
72
+ end
73
+
74
+ # @api private
75
+ #
76
+ # Deregisters a slave-to-PID mapping
77
+ #
78
+ # @return [(Autorespawn::Slave,Integer)] the slave object and unique
79
+ # slave ID that were associated with the slave
80
+ # @raise [ArgumentError] if there is no slave associated with the
81
+ # PID
82
+ def deregister_slave_pid(pid)
83
+ if slave = pid_to_slave.delete(pid)
84
+ return slave, slave_to_id[slave]
85
+ else
86
+ raise ArgumentError, "no slave known for #{pid}"
87
+ end
88
+ end
89
+
90
+ def initialize(server, manager, io: STDOUT)
91
+ @io = io
92
+ @slave_id = 0
93
+ @slave_to_id = Hash.new
94
+ @pid_to_slave = Hash.new
95
+ manager.on_slave_new do |slave|
96
+ slave_id = register_slave(slave)
97
+ io.puts "[##{slave_id}] new slave #{slave_to_s(slave)}"
98
+ end
99
+ manager.on_slave_start do |slave|
100
+ slave_id = register_slave_pid(slave)
101
+ io.puts "[##{slave_id}] slave #{slave_to_s(slave)} started (PID=#{slave.pid})"
102
+ end
103
+ manager.on_slave_finished do |slave|
104
+ slave, slave_id = deregister_slave_pid(slave.pid)
105
+ io.puts "[##{slave_id}] slave #{slave_to_s(slave)} finished (PID=#{slave.pid})"
106
+ end
107
+ server.on_exception do |pid, exception|
108
+ slave, slave_id = slave_from_pid(pid)
109
+ io.puts "[##{slave_id}] #{slave_to_s(slave)} reports exception"
110
+ Roby.display_exception(io, exception)
111
+ end
112
+ server.on_discovery_start do |pid|
113
+ slave, slave_id = slave_from_pid(pid)
114
+ io.puts "[##{slave_id}] #{slave_to_s(slave)} started discovery"
115
+ end
116
+ server.on_discovery_finished do |pid|
117
+ slave, slave_id = slave_from_pid(pid)
118
+ io.puts "[##{slave_id}] #{slave_to_s(slave)} finished discovery"
119
+ end
120
+ server.on_test_start do |pid|
121
+ slave, slave_id = slave_from_pid(pid)
122
+ io.puts "[##{slave_id}] #{slave_to_s(slave)} started testing"
123
+ end
124
+ server.on_test_result do |pid, file, test_case_name, test_name, failures, assertions, time|
125
+ slave, slave_id = slave_from_pid(pid)
126
+ io.puts "[##{slave_id}] #{test_case_name}##{test_name}: #{failures.size} failures and #{assertions.size} assertions (#{time})"
127
+ failures.each do |e|
128
+ Roby.display_exception(io, e)
129
+ end
130
+ end
131
+ server.on_test_finished do |pid|
132
+ slave, slave_id = slave_from_pid(pid)
133
+ io.puts "[##{slave_id}] #{slave_to_s(slave)} finished testing"
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,21 @@
1
+ module Roby
2
+ module App
3
+ DEFAULT_ROBOT_NAME = 'default'
4
+ DEFAULT_ROBOT_TYPE = 'default'
5
+
6
+ # Resolves the ROBOT keyword in the given path
7
+ #
8
+ # @param [String] path
9
+ # @param [String] robot_name
10
+ # @return [String]
11
+ def self.resolve_robot_in_path(path, robot_name = Roby.app.robot_name)
12
+ if robot_name == DEFAULT_ROBOT_NAME
13
+ robot_name = ""
14
+ end
15
+ robot_name ||= ""
16
+
17
+ path.gsub(/ROBOT/, robot_name).
18
+ gsub(/\/\//, '/')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,2 @@
1
+ require 'roby/app/cucumber/helpers'
2
+ require 'roby/app/cucumber/controller'
@@ -0,0 +1,439 @@
1
+ require 'roby/interface/async'
2
+
3
+ module Roby
4
+ module App
5
+ module Cucumber
6
+ # API that starts and communicates with a Roby controller for the
7
+ # benefit of a Cucumber scenario
8
+ class Controller
9
+ class InvalidState < RuntimeError; end
10
+
11
+ # The PID of the started Roby process
12
+ #
13
+ # @return [Integer,nil]
14
+ attr_reader :roby_pid
15
+
16
+ # The object used to communicate with the Roby instance
17
+ #
18
+ # It is set only after {#roby_wait} was called (or after a
19
+ # {#roby_start} whose wait parameter was set to true)
20
+ #
21
+ # @return [Roby::Interface::Client,nil]
22
+ attr_reader :roby_interface
23
+
24
+ # The set of jobs started by {#start_monitoring_job}
25
+ attr_reader :background_jobs
26
+
27
+ # The batch that gathers all the interface operations that will
28
+ # be executed at the next #run_job
29
+ attr_reader :current_batch
30
+
31
+ # Actions that would be started by {#current_batch}
32
+ attr_reader :pending_actions
33
+
34
+ # Whether the process should abort when an error is detected, or
35
+ # keep running the actions as-is. The latter is useful for
36
+ # debugging
37
+ #
38
+ # Active the keep running mode by setting CUCUMBER_KEEP_RUNNING
39
+ # to 1
40
+ attr_predicate :keep_running?, true
41
+
42
+ # Whether we run the jobs, or only validate their existence and
43
+ # arguments
44
+ #
45
+ # The validation mode is activated by setting
46
+ # ROBY_VALIDATE_STEPS to '1'
47
+ attr_predicate :validation_mode?, true
48
+
49
+ # Whether this started a Roby controller
50
+ def roby_running?
51
+ !!@roby_pid
52
+ end
53
+
54
+ # Whether we have a connection to the started Roby controller
55
+ def roby_connected?
56
+ roby_interface.connected?
57
+ end
58
+
59
+ def initialize(port: Roby::Interface::DEFAULT_PORT,
60
+ keep_running: (ENV['CUCUMBER_KEEP_RUNNING'] == '1'),
61
+ validation_mode: (ENV['ROBY_VALIDATE_STEPS'] == '1'))
62
+ @roby_pid = nil
63
+ @roby_interface = Roby::Interface::Async::Interface.
64
+ new('localhost', port: port)
65
+ @background_jobs = Array.new
66
+ @keep_running = keep_running
67
+ @validation_mode = validation_mode
68
+ @pending_actions = []
69
+ end
70
+
71
+ # Start a Roby controller
72
+ #
73
+ # @param [String] robot_name the name of the robot configuration
74
+ # @param [String] robot_type the type of the robot configuration
75
+ # @param [Boolean] wait whether the method should wait for a
76
+ # successful connection to the Roby application
77
+ # @param [Boolean] controller whether the configuration's controller
78
+ # blocks should be executed
79
+ # @param [Hash] state initial values for the state
80
+ #
81
+ # @raise InvalidState if a controller is already running
82
+ def roby_start(robot_name, robot_type, connect: true, controller: true, app_dir: Dir.pwd, log_dir: nil, state: Hash.new, **spawn_options)
83
+ if roby_running?
84
+ raise InvalidState, "a Roby controller is already running, call #roby_stop and #roby_join first"
85
+ end
86
+
87
+ options = Array.new
88
+ if log_dir
89
+ options << "--log-dir=#{log_dir}"
90
+ end
91
+ @roby_pid = spawn Gem.ruby, File.join(Roby::BIN_DIR, "roby"), 'run',
92
+ "--robot=#{robot_name},#{robot_type}",
93
+ '--controller',
94
+ '--quiet',
95
+ *options,
96
+ *state.map { |k, v| "--set=#{k}=#{v}" },
97
+ chdir: app_dir,
98
+ pgroup: 0,
99
+ **spawn_options
100
+ if connect
101
+ roby_connect
102
+ end
103
+ roby_pid
104
+ end
105
+
106
+ # Try connecting to the Roby controller
107
+ #
108
+ # It sets {#roby_interface} on success
109
+ #
110
+ # @return [Roby::Interface::Client,nil] a valid interface object
111
+ # if the connection was successful, and nil otherwise
112
+ def roby_try_connect
113
+ if !roby_interface.connecting? && !roby_interface.connected?
114
+ roby_interface.attempt_connection
115
+ end
116
+ roby_interface.poll
117
+ roby_interface.connected?
118
+ end
119
+
120
+ # Wait for the Roby controller started with {#roby_start} to be
121
+ # available
122
+ def roby_connect
123
+ if roby_connected?
124
+ raise InvalidState, "already connected"
125
+ end
126
+
127
+ while !roby_connected?
128
+ roby_try_connect
129
+ _, status = Process.waitpid2(roby_pid, Process::WNOHANG)
130
+ if status
131
+ raise InvalidState, "remote Roby controller quit before we could get a connection"
132
+ end
133
+ roby_interface.wait
134
+ end
135
+ @current_batch = @roby_interface.create_batch
136
+ end
137
+
138
+ # Disconnect the interface to the controller, but does not stop
139
+ # the controller
140
+ def roby_disconnect
141
+ if !roby_connected?
142
+ raise InvalidState, "not connected"
143
+ end
144
+
145
+ @roby_interface.close
146
+ end
147
+
148
+ # Stops an already started Roby controller
149
+ #
150
+ # @raise InvalidState if no controllers were started
151
+ def roby_stop(join: true)
152
+ if !roby_running?
153
+ raise InvalidState, "cannot call #roby_stop if no controllers were started"
154
+ elsif !roby_connected?
155
+ raise InvalidState, "you need to successfully connect to the Roby controller with #roby_connect before you can call #roby_stop"
156
+ end
157
+
158
+ begin
159
+ roby_interface.quit
160
+ rescue Interface::ComError
161
+ ensure
162
+ roby_interface.close
163
+ end
164
+
165
+ roby_join if join
166
+ end
167
+
168
+ # Kill the Roby controller process
169
+ def roby_kill(join: true)
170
+ if !roby_running?
171
+ raise InvalidState, "cannot call #roby_stop if no controllers were started"
172
+ end
173
+
174
+ Process.kill('INT', roby_pid)
175
+ roby_join if join
176
+ end
177
+
178
+
179
+ # Wait for the remote process to quit
180
+ def roby_join
181
+ if !roby_running?
182
+ raise InvalidState, "cannot call #roby_join without a running Roby controller"
183
+ end
184
+
185
+ _, status = Process.waitpid2(roby_pid)
186
+ @roby_pid = nil
187
+ status
188
+ rescue Errno::ECHILD
189
+ @roby_pid = nil
190
+ end
191
+
192
+ # Wait for the remote process to quit
193
+ #
194
+ # It raises an exception if the process does not terminate
195
+ # successfully
196
+ def roby_join!
197
+ if (status = roby_join) && !status.success?
198
+ raise InvalidState, "Roby process exited with status #{status}"
199
+ end
200
+ rescue Errno::ENOCHILD
201
+ @roby_pid = nil
202
+ end
203
+
204
+ # Enable or disable backtrace filtering on the Roby instance
205
+ def roby_enable_backtrace_filtering(enable: true)
206
+ if !roby_connected?
207
+ raise InvalidState, "you need to successfully connect to the Roby controller with #roby_connect before you can call #roby_enable_backtrace_filtering"
208
+ end
209
+ roby_interface.client.enable_backtrace_filtering(enable: enable)
210
+ end
211
+
212
+ # The log dir of the Roby app
213
+ #
214
+ # Since the roby app is local, this is a valid local path
215
+ def roby_log_dir
216
+ roby_interface.client.log_dir
217
+ end
218
+
219
+ # Exception raised when an monitor failed while an action was
220
+ # running
221
+ class FailedBackgroundJob < RuntimeError; end
222
+
223
+ # Exception raised when an action finished with any other state
224
+ # than 'success'
225
+ class FailedAction < RuntimeError; end
226
+
227
+ BackgroundJob = Struct.new :action_monitor, :description, :monitoring do
228
+ def job_id
229
+ action_monitor.job_id
230
+ end
231
+ def success?
232
+ action_monitor.success?
233
+ end
234
+ def terminated?
235
+ action_monitor.terminated?
236
+ end
237
+ def monitoring?
238
+ monitoring
239
+ end
240
+ end
241
+
242
+ # The job ID of the last started
243
+ #
244
+ # @return [nil,Integer] nil if the job has not yet been started,
245
+ # and the ID otherwise. It's the caller responsibility to call
246
+ # {#apply_current_batch}
247
+ def last_main_job_id
248
+ if job = each_main_job.to_a.last
249
+ job.job_id
250
+ end
251
+ end
252
+
253
+ # Start a job in the background
254
+ #
255
+ # Its failure will make the next #run_job step fail. Unlike a
256
+ # job created by {#start_monitoring_job}, it will not be stopped
257
+ # when {#run_job} is called.
258
+ def start_job(description, m, arguments = Hash.new)
259
+ if @has_run_job
260
+ drop_all_jobs if !validation_mode?
261
+ @has_run_job = false
262
+ end
263
+ __start_job(description, m, arguments, false)
264
+ end
265
+
266
+ # Start a background action whose failure will make the next
267
+ # #run_job step fail
268
+ #
269
+ # This action will be stopped at the end of the next {#run_job}
270
+ def start_monitoring_job(description, m, arguments = Hash.new)
271
+ __start_job(description, m, arguments, true)
272
+ end
273
+
274
+ # @api private
275
+ #
276
+ # Helper job-starting method
277
+ def __start_job(description, m, arguments, monitoring)
278
+ if validation_mode?
279
+ validate_job(m, arguments)
280
+ return
281
+ end
282
+
283
+ action = Interface::Async::ActionMonitor.new(roby_interface, m, arguments)
284
+ action.restart(batch: current_batch)
285
+ pending_actions << action
286
+ background_jobs << BackgroundJob.new(action, description, monitoring)
287
+ action
288
+ end
289
+
290
+ # Enumerate all jobs started with {#start_monitoring_job}
291
+ def each_monitoring_job
292
+ return enum_for(__method__) if !block_given?
293
+ background_jobs.each do |job|
294
+ yield(job) if job.monitoring?
295
+ end
296
+ end
297
+
298
+ # Enumerate all jobs started with {#start_job}
299
+ #
300
+ # These jobs are usually the job-under-test, hence the 'main'
301
+ # moniker
302
+ def each_main_job
303
+ return enum_for(__method__) if !block_given?
304
+ background_jobs.each do |job|
305
+ yield(job) if !job.monitoring?
306
+ end
307
+ end
308
+
309
+ # Find one monitoring job that failed
310
+ def find_failed_monitoring_job
311
+ each_monitoring_job.find do |background_job|
312
+ background_job.terminated? && !background_job.success?
313
+ end
314
+ end
315
+
316
+ # @api private
317
+ #
318
+ # Poll the interface until the block returns a truthy value
319
+ def roby_poll_interface_until
320
+ while !(result = yield)
321
+ if defined?(::Cucumber) && ::Cucumber.wants_to_quit
322
+ raise Interrupt, "Interrupted"
323
+ end
324
+ roby_interface.poll
325
+ roby_interface.wait
326
+ end
327
+ result
328
+ end
329
+
330
+ def apply_current_batch(*actions, sync: true)
331
+ return if current_batch.empty?
332
+
333
+ batch_result = current_batch.__process
334
+ if sync
335
+ roby_poll_interface_until do
336
+ (pending_actions + actions).all? { |act| act.async }
337
+ end
338
+ end
339
+ batch_result
340
+ ensure
341
+ @current_batch = roby_interface.create_batch
342
+ @pending_actions = Array.new
343
+ end
344
+
345
+ # Start an action
346
+ def run_job(m, arguments = Hash.new)
347
+ if validation_mode?
348
+ validate_job(m, arguments)
349
+ return
350
+ end
351
+
352
+ action = Interface::Async::ActionMonitor.new(roby_interface, m, arguments)
353
+ action.restart(batch: current_batch)
354
+ apply_current_batch(action)
355
+ @has_run_job = true
356
+
357
+ failed_monitor = roby_poll_interface_until do
358
+ if action.terminated?
359
+ break
360
+ else
361
+ find_failed_monitoring_job
362
+ end
363
+ end
364
+
365
+ if action.success?
366
+ return
367
+ elsif failed_monitor
368
+ if keep_running?
369
+ STDERR.puts
370
+ STDERR.puts "FAILED: monitoring job #{failed_monitor.description} failed"
371
+ STDERR.puts "In 'keep running' mode. Interrupt with CTRL+C"
372
+ roby_poll_interface_until { false }
373
+ else
374
+ raise FailedBackgroundJob, "monitoring job #{failed_monitor.description} failed"
375
+ end
376
+ else
377
+ if keep_running?
378
+ STDERR.puts
379
+ STDERR.puts "FAILED: action #{m} failed"
380
+ STDERR.puts "In 'keep running' mode. Interrupt with CTRL+C"
381
+ roby_poll_interface_until { false }
382
+ else
383
+ raise FailedAction, "action #{m} failed"
384
+ end
385
+ end
386
+
387
+ ensure
388
+ # Kill the monitoring actions as well as the main actions
389
+ drop_monitoring_jobs(*Array(action))
390
+ end
391
+
392
+ # Raised when validating the jobs
393
+ class InvalidJob < ArgumentError; end
394
+
395
+ # @api private
396
+ #
397
+ # Validate that the given action name and arguments match the
398
+ # interface's description
399
+ def validate_job(m, arguments)
400
+ if !(action = roby_interface.client.find_action_by_name(m))
401
+ raise InvalidJob, "no action is named '#{m}'"
402
+ end
403
+ arguments = arguments.dup
404
+ action.arguments.each do |arg|
405
+ arg_sym = arg.name.to_sym
406
+ has_arg = arguments.has_key?(arg_sym)
407
+ if !has_arg && arg.required?
408
+ raise InvalidJob, "#{m} requires an argument named #{arg.name} which is not provided"
409
+ end
410
+ arguments.delete(arg_sym)
411
+ end
412
+ if !arguments.empty?
413
+ raise InvalidJob, "arguments #{arguments.keys.map(&:to_s).sort.join(", ")} are not declared arguments of #{m}"
414
+ end
415
+ end
416
+
417
+ def drop_all_jobs(*extra_jobs)
418
+ jobs, @background_jobs =
419
+ background_jobs, Array.new
420
+ drop_jobs(*extra_jobs, *jobs.map(&:action_monitor))
421
+ end
422
+
423
+ def drop_monitoring_jobs(*extra_jobs)
424
+ monitoring_jobs, @background_jobs =
425
+ background_jobs.partition { |j| j.monitoring? }
426
+ drop_jobs(*extra_jobs, *monitoring_jobs.map(&:action_monitor))
427
+ end
428
+
429
+ def drop_jobs(*jobs)
430
+ jobs.each do |act|
431
+ if !act.terminated? && act.async
432
+ act.drop(batch: current_batch)
433
+ end
434
+ end
435
+ end
436
+ end
437
+ end
438
+ end
439
+ end