roby 0.7

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 (240) hide show
  1. data/.gitignore +29 -0
  2. data/History.txt +4 -0
  3. data/License-fr.txt +519 -0
  4. data/License.txt +515 -0
  5. data/Manifest.txt +245 -0
  6. data/NOTES +4 -0
  7. data/README.txt +163 -0
  8. data/Rakefile +161 -0
  9. data/TODO.txt +146 -0
  10. data/app/README.txt +24 -0
  11. data/app/Rakefile +8 -0
  12. data/app/config/ROBOT.rb +5 -0
  13. data/app/config/app.yml +91 -0
  14. data/app/config/init.rb +7 -0
  15. data/app/config/roby.yml +3 -0
  16. data/app/controllers/.gitattributes +0 -0
  17. data/app/controllers/ROBOT.rb +2 -0
  18. data/app/data/.gitattributes +0 -0
  19. data/app/planners/ROBOT/main.rb +6 -0
  20. data/app/planners/main.rb +5 -0
  21. data/app/scripts/distributed +3 -0
  22. data/app/scripts/generate/bookmarks +3 -0
  23. data/app/scripts/replay +3 -0
  24. data/app/scripts/results +3 -0
  25. data/app/scripts/run +3 -0
  26. data/app/scripts/server +3 -0
  27. data/app/scripts/shell +3 -0
  28. data/app/scripts/test +3 -0
  29. data/app/tasks/.gitattributes +0 -0
  30. data/app/tasks/ROBOT/.gitattributes +0 -0
  31. data/bin/roby +210 -0
  32. data/bin/roby-log +168 -0
  33. data/bin/roby-shell +25 -0
  34. data/doc/images/event_generalization.png +0 -0
  35. data/doc/images/exception_propagation_1.png +0 -0
  36. data/doc/images/exception_propagation_2.png +0 -0
  37. data/doc/images/exception_propagation_3.png +0 -0
  38. data/doc/images/exception_propagation_4.png +0 -0
  39. data/doc/images/exception_propagation_5.png +0 -0
  40. data/doc/images/replay_handler_error.png +0 -0
  41. data/doc/images/replay_handler_error_0.png +0 -0
  42. data/doc/images/replay_handler_error_1.png +0 -0
  43. data/doc/images/roby_cycle_overview.png +0 -0
  44. data/doc/images/roby_replay_02.png +0 -0
  45. data/doc/images/roby_replay_03.png +0 -0
  46. data/doc/images/roby_replay_04.png +0 -0
  47. data/doc/images/roby_replay_event_representation.png +0 -0
  48. data/doc/images/roby_replay_first_state.png +0 -0
  49. data/doc/images/roby_replay_relations.png +0 -0
  50. data/doc/images/roby_replay_startup.png +0 -0
  51. data/doc/images/task_event_generalization.png +0 -0
  52. data/doc/papers.rdoc +11 -0
  53. data/doc/styles/allison.css +314 -0
  54. data/doc/styles/allison.js +316 -0
  55. data/doc/styles/allison.rb +276 -0
  56. data/doc/styles/jamis.rb +593 -0
  57. data/doc/tutorials/01-GettingStarted.rdoc +86 -0
  58. data/doc/tutorials/02-GoForward.rdoc +220 -0
  59. data/doc/tutorials/03-PlannedPath.rdoc +268 -0
  60. data/doc/tutorials/04-EventPropagation.rdoc +236 -0
  61. data/doc/tutorials/05-ErrorHandling.rdoc +319 -0
  62. data/doc/tutorials/06-Overview.rdoc +40 -0
  63. data/doc/videos.rdoc +69 -0
  64. data/ext/droby/dump.cc +175 -0
  65. data/ext/droby/extconf.rb +3 -0
  66. data/ext/graph/algorithm.cc +746 -0
  67. data/ext/graph/extconf.rb +7 -0
  68. data/ext/graph/graph.cc +529 -0
  69. data/ext/graph/graph.hh +183 -0
  70. data/ext/graph/iterator_sequence.hh +102 -0
  71. data/ext/graph/undirected_dfs.hh +226 -0
  72. data/ext/graph/undirected_graph.hh +421 -0
  73. data/lib/roby.rb +41 -0
  74. data/lib/roby/app.rb +870 -0
  75. data/lib/roby/app/rake.rb +56 -0
  76. data/lib/roby/app/run.rb +14 -0
  77. data/lib/roby/app/scripts/distributed.rb +13 -0
  78. data/lib/roby/app/scripts/generate/bookmarks.rb +162 -0
  79. data/lib/roby/app/scripts/replay.rb +31 -0
  80. data/lib/roby/app/scripts/results.rb +15 -0
  81. data/lib/roby/app/scripts/run.rb +26 -0
  82. data/lib/roby/app/scripts/server.rb +18 -0
  83. data/lib/roby/app/scripts/shell.rb +88 -0
  84. data/lib/roby/app/scripts/test.rb +40 -0
  85. data/lib/roby/basic_object.rb +151 -0
  86. data/lib/roby/config.rb +5 -0
  87. data/lib/roby/control.rb +747 -0
  88. data/lib/roby/decision_control.rb +17 -0
  89. data/lib/roby/distributed.rb +32 -0
  90. data/lib/roby/distributed/base.rb +440 -0
  91. data/lib/roby/distributed/communication.rb +871 -0
  92. data/lib/roby/distributed/connection_space.rb +592 -0
  93. data/lib/roby/distributed/distributed_object.rb +206 -0
  94. data/lib/roby/distributed/drb.rb +62 -0
  95. data/lib/roby/distributed/notifications.rb +539 -0
  96. data/lib/roby/distributed/peer.rb +550 -0
  97. data/lib/roby/distributed/protocol.rb +529 -0
  98. data/lib/roby/distributed/proxy.rb +343 -0
  99. data/lib/roby/distributed/subscription.rb +311 -0
  100. data/lib/roby/distributed/transaction.rb +498 -0
  101. data/lib/roby/event.rb +897 -0
  102. data/lib/roby/exceptions.rb +234 -0
  103. data/lib/roby/executives/simple.rb +30 -0
  104. data/lib/roby/graph.rb +166 -0
  105. data/lib/roby/interface.rb +390 -0
  106. data/lib/roby/log.rb +3 -0
  107. data/lib/roby/log/chronicle.rb +303 -0
  108. data/lib/roby/log/console.rb +72 -0
  109. data/lib/roby/log/data_stream.rb +197 -0
  110. data/lib/roby/log/dot.rb +279 -0
  111. data/lib/roby/log/event_stream.rb +151 -0
  112. data/lib/roby/log/file.rb +340 -0
  113. data/lib/roby/log/gui/basic_display.ui +83 -0
  114. data/lib/roby/log/gui/chronicle.rb +26 -0
  115. data/lib/roby/log/gui/chronicle_view.rb +40 -0
  116. data/lib/roby/log/gui/chronicle_view.ui +70 -0
  117. data/lib/roby/log/gui/data_displays.rb +172 -0
  118. data/lib/roby/log/gui/data_displays.ui +155 -0
  119. data/lib/roby/log/gui/notifications.rb +26 -0
  120. data/lib/roby/log/gui/relations.rb +248 -0
  121. data/lib/roby/log/gui/relations.ui +123 -0
  122. data/lib/roby/log/gui/relations_view.rb +185 -0
  123. data/lib/roby/log/gui/relations_view.ui +149 -0
  124. data/lib/roby/log/gui/replay.rb +327 -0
  125. data/lib/roby/log/gui/replay_controls.rb +200 -0
  126. data/lib/roby/log/gui/replay_controls.ui +259 -0
  127. data/lib/roby/log/gui/runtime.rb +130 -0
  128. data/lib/roby/log/hooks.rb +185 -0
  129. data/lib/roby/log/logger.rb +202 -0
  130. data/lib/roby/log/notifications.rb +244 -0
  131. data/lib/roby/log/plan_rebuilder.rb +470 -0
  132. data/lib/roby/log/relations.rb +1056 -0
  133. data/lib/roby/log/server.rb +550 -0
  134. data/lib/roby/log/sqlite.rb +47 -0
  135. data/lib/roby/log/timings.rb +164 -0
  136. data/lib/roby/plan-object.rb +247 -0
  137. data/lib/roby/plan.rb +762 -0
  138. data/lib/roby/planning.rb +13 -0
  139. data/lib/roby/planning/loops.rb +302 -0
  140. data/lib/roby/planning/model.rb +906 -0
  141. data/lib/roby/planning/task.rb +151 -0
  142. data/lib/roby/propagation.rb +562 -0
  143. data/lib/roby/query.rb +619 -0
  144. data/lib/roby/relations.rb +583 -0
  145. data/lib/roby/relations/conflicts.rb +70 -0
  146. data/lib/roby/relations/ensured.rb +20 -0
  147. data/lib/roby/relations/error_handling.rb +23 -0
  148. data/lib/roby/relations/events.rb +9 -0
  149. data/lib/roby/relations/executed_by.rb +193 -0
  150. data/lib/roby/relations/hierarchy.rb +239 -0
  151. data/lib/roby/relations/influence.rb +10 -0
  152. data/lib/roby/relations/planned_by.rb +63 -0
  153. data/lib/roby/robot.rb +7 -0
  154. data/lib/roby/standard_errors.rb +218 -0
  155. data/lib/roby/state.rb +5 -0
  156. data/lib/roby/state/events.rb +221 -0
  157. data/lib/roby/state/information.rb +55 -0
  158. data/lib/roby/state/pos.rb +110 -0
  159. data/lib/roby/state/shapes.rb +32 -0
  160. data/lib/roby/state/state.rb +353 -0
  161. data/lib/roby/support.rb +92 -0
  162. data/lib/roby/task-operations.rb +182 -0
  163. data/lib/roby/task.rb +1618 -0
  164. data/lib/roby/test/common.rb +399 -0
  165. data/lib/roby/test/distributed.rb +214 -0
  166. data/lib/roby/test/tasks/empty_task.rb +9 -0
  167. data/lib/roby/test/tasks/goto.rb +36 -0
  168. data/lib/roby/test/tasks/simple_task.rb +23 -0
  169. data/lib/roby/test/testcase.rb +519 -0
  170. data/lib/roby/test/tools.rb +160 -0
  171. data/lib/roby/thread_task.rb +87 -0
  172. data/lib/roby/transactions.rb +462 -0
  173. data/lib/roby/transactions/proxy.rb +292 -0
  174. data/lib/roby/transactions/updates.rb +139 -0
  175. data/plugins/fault_injection/History.txt +4 -0
  176. data/plugins/fault_injection/README.txt +37 -0
  177. data/plugins/fault_injection/Rakefile +18 -0
  178. data/plugins/fault_injection/TODO.txt +0 -0
  179. data/plugins/fault_injection/app.rb +52 -0
  180. data/plugins/fault_injection/fault_injection.rb +89 -0
  181. data/plugins/fault_injection/test/test_fault_injection.rb +84 -0
  182. data/plugins/subsystems/README.txt +40 -0
  183. data/plugins/subsystems/Rakefile +18 -0
  184. data/plugins/subsystems/app.rb +171 -0
  185. data/plugins/subsystems/test/app/README +24 -0
  186. data/plugins/subsystems/test/app/Rakefile +8 -0
  187. data/plugins/subsystems/test/app/config/app.yml +71 -0
  188. data/plugins/subsystems/test/app/config/init.rb +9 -0
  189. data/plugins/subsystems/test/app/config/roby.yml +3 -0
  190. data/plugins/subsystems/test/app/planners/main.rb +20 -0
  191. data/plugins/subsystems/test/app/scripts/distributed +3 -0
  192. data/plugins/subsystems/test/app/scripts/replay +3 -0
  193. data/plugins/subsystems/test/app/scripts/results +3 -0
  194. data/plugins/subsystems/test/app/scripts/run +3 -0
  195. data/plugins/subsystems/test/app/scripts/server +3 -0
  196. data/plugins/subsystems/test/app/scripts/shell +3 -0
  197. data/plugins/subsystems/test/app/scripts/test +3 -0
  198. data/plugins/subsystems/test/app/tasks/services.rb +15 -0
  199. data/plugins/subsystems/test/test_subsystems.rb +71 -0
  200. data/test/distributed/test_communication.rb +178 -0
  201. data/test/distributed/test_connection.rb +282 -0
  202. data/test/distributed/test_execution.rb +373 -0
  203. data/test/distributed/test_mixed_plan.rb +341 -0
  204. data/test/distributed/test_plan_notifications.rb +238 -0
  205. data/test/distributed/test_protocol.rb +516 -0
  206. data/test/distributed/test_query.rb +102 -0
  207. data/test/distributed/test_remote_plan.rb +491 -0
  208. data/test/distributed/test_transaction.rb +463 -0
  209. data/test/mockups/tasks.rb +27 -0
  210. data/test/planning/test_loops.rb +380 -0
  211. data/test/planning/test_model.rb +427 -0
  212. data/test/planning/test_task.rb +106 -0
  213. data/test/relations/test_conflicts.rb +42 -0
  214. data/test/relations/test_ensured.rb +38 -0
  215. data/test/relations/test_executed_by.rb +149 -0
  216. data/test/relations/test_hierarchy.rb +158 -0
  217. data/test/relations/test_planned_by.rb +54 -0
  218. data/test/suite_core.rb +24 -0
  219. data/test/suite_distributed.rb +9 -0
  220. data/test/suite_planning.rb +3 -0
  221. data/test/suite_relations.rb +8 -0
  222. data/test/test_bgl.rb +508 -0
  223. data/test/test_control.rb +399 -0
  224. data/test/test_event.rb +894 -0
  225. data/test/test_exceptions.rb +592 -0
  226. data/test/test_interface.rb +37 -0
  227. data/test/test_log.rb +114 -0
  228. data/test/test_log_server.rb +132 -0
  229. data/test/test_plan.rb +584 -0
  230. data/test/test_propagation.rb +210 -0
  231. data/test/test_query.rb +266 -0
  232. data/test/test_relations.rb +180 -0
  233. data/test/test_state.rb +414 -0
  234. data/test/test_support.rb +16 -0
  235. data/test/test_task.rb +938 -0
  236. data/test/test_testcase.rb +122 -0
  237. data/test/test_thread_task.rb +73 -0
  238. data/test/test_transactions.rb +569 -0
  239. data/test/test_transactions_proxy.rb +198 -0
  240. metadata +570 -0
@@ -0,0 +1,516 @@
1
+ $LOAD_PATH.unshift File.expand_path('../..', File.dirname(__FILE__))
2
+ require 'roby/test/distributed'
3
+ require 'roby/test/tasks/simple_task'
4
+ require 'flexmock'
5
+
6
+ class TC_DistributedRobyProtocol < Test::Unit::TestCase
7
+ include Roby::Distributed::Test
8
+
9
+ def test_remote_id
10
+ remote = remote_server do
11
+ def remote_object
12
+ @object ||= Object.new
13
+ @object.remote_id
14
+ end
15
+ end
16
+
17
+ assert_equal(remote.remote_object, remote.remote_object)
18
+
19
+ h = Hash.new
20
+ h[remote.remote_object] = 1
21
+ assert_equal(1, h[remote.remote_object])
22
+
23
+ s = Set.new
24
+ s << remote.remote_object
25
+ assert(s.include?(remote.remote_object))
26
+
27
+ object = Object.new
28
+ assert_equal(object, object.remote_id.local_object)
29
+ end
30
+
31
+ TEST_ARRAY_SIZE = 7
32
+ def dumpable_array
33
+ task = Roby::Task.new(:id => 1)
34
+ [1, task,
35
+ Roby::EventGenerator.new {},
36
+ SimpleTask.new(:id => 2),
37
+ task.event(:start),
38
+ Roby::TaskStructure::Hierarchy,
39
+ Class.new(Task).new(:id => 3) ]
40
+ end
41
+ def dumpable_hash
42
+ Hash[*(0...TEST_ARRAY_SIZE).zip(dumpable_array).flatten]
43
+ end
44
+ def check_undumped_array(array, recursive = true)
45
+ assert_equal(TEST_ARRAY_SIZE, array.size)
46
+ assert_equal(1, array[0])
47
+
48
+ assert_kind_of(Task::DRoby, array[1])
49
+ assert_equal({:id => 1}, array[1].arguments)
50
+ assert_equal(Task, array[1].model.proxy(remote_peer))
51
+
52
+ assert_kind_of(EventGenerator::DRoby, array[2])
53
+ assert(array[2].controlable)
54
+ assert_equal(EventGenerator, array[2].model.proxy(remote_peer))
55
+
56
+ assert_kind_of(Task::DRoby, array[3])
57
+ assert_equal({:id => 2}, array[3].arguments)
58
+ assert_equal(SimpleTask, array[3].model.proxy(remote_peer))
59
+
60
+ assert_kind_of(TaskEventGenerator::DRoby, array[4])
61
+ assert_equal(array[1].remote_siblings, array[4].task.remote_siblings)
62
+ assert_equal(:start, array[4].symbol)
63
+
64
+ assert_kind_of(Roby::Distributed::DRobyConstant, array[5])
65
+ assert_equal(Roby::TaskStructure::Hierarchy.object_id, array[5].proxy(nil).object_id)
66
+
67
+ assert_kind_of(Task::DRoby, array[6])
68
+ assert_not_equal(Task, array[6].model.proxy(remote_peer))
69
+
70
+ array.each do |element|
71
+ assert_nothing_raised(element.to_s) { Marshal.dump(element) }
72
+ end
73
+ dumped = nil
74
+ assert_nothing_raised { dumped = Marshal.dump(array) }
75
+
76
+ if recursive
77
+ check_undumped_array(Marshal.load(dumped), false)
78
+ end
79
+ end
80
+
81
+ def test_array_droby_dump
82
+ FlexMock.use do |mock|
83
+ mock.should_receive(:droby_dump).and_return("mock")
84
+ array = [1, mock]
85
+ assert_equal([1, "mock"], array.droby_dump(nil))
86
+ end
87
+ end
88
+
89
+ def test_set_droby_dump
90
+ FlexMock.use do |mock|
91
+ mock.should_receive(:droby_dump).and_return("mock")
92
+ set = [1, mock, "q"].to_set
93
+ assert_equal([1, "mock", "q"].to_set, set.droby_dump(nil))
94
+ end
95
+ end
96
+
97
+ def test_hash_droby_dump
98
+ FlexMock.use do |mock|
99
+ mock.should_receive(:droby_dump).and_return("mock")
100
+ hash = { 1 => mock, mock => "q" }
101
+ assert_equal({ 1 => "mock", "mock" => "q" }, hash.droby_dump(nil))
102
+ end
103
+ end
104
+
105
+ def test_value_set_droby_dump
106
+ FlexMock.use do |mock|
107
+ mock.should_receive(:droby_dump).and_return("mock")
108
+ value_set = [1, mock, "q"].to_value_set
109
+
110
+
111
+ dumped = value_set.droby_dump(nil)
112
+ assert_kind_of(ValueSet, dumped)
113
+ assert_equal([1, "mock", "q"].to_set, dumped.to_set)
114
+ end
115
+ end
116
+
117
+
118
+ def test_enumerables
119
+ test_case = self
120
+ peer2peer(true) do |remote|
121
+ PeerServer.class_eval do
122
+ define_method(:array) { test_case.dumpable_array }
123
+ define_method(:value_set) { test_case.dumpable_array.to_value_set }
124
+ define_method(:_hash) { test_case.dumpable_hash }
125
+ define_method(:array_of_array) { [test_case.dumpable_array] }
126
+ end
127
+ end
128
+
129
+ array = remote_peer.call(:array)
130
+ assert_kind_of(Array, array)
131
+ check_undumped_array(array)
132
+
133
+ hash = remote_peer.call(:_hash)
134
+ assert_kind_of(Hash, hash)
135
+ check_undumped_array(hash)
136
+
137
+ array_of_array = remote_peer.call(:array_of_array)
138
+ assert_kind_of(Array, array_of_array)
139
+ check_undumped_array(array_of_array[0])
140
+
141
+ set = remote_peer.call(:value_set)
142
+ assert_kind_of(ValueSet, set)
143
+ assert_equal(TEST_ARRAY_SIZE, set.size)
144
+ assert(set.find { |o| o == 1 })
145
+ assert(set.find { |t| t.kind_of?(Task::DRoby) && t.arguments[:id] == 1 })
146
+ assert(set.find { |e| e.kind_of?(EventGenerator::DRoby) })
147
+ assert(set.find { |t| t.kind_of?(Task::DRoby) && t.arguments[:id] == 2 })
148
+ end
149
+
150
+ def test_marshal_peer
151
+ peer2peer(true) do |remote|
152
+ def remote.remote_peer_id; Distributed.state.remote_id end
153
+ end
154
+
155
+ m_local = remote_peer.call(:peer)
156
+ assert_equal(Distributed.remote_id, m_local.peer_id)
157
+ assert_equal(Roby::Distributed, m_local.proxy(nil))
158
+ assert_equal(remote_peer.remote_id, remote.remote_peer_id)
159
+ end
160
+
161
+ def test_marshal_model
162
+ peer2peer(true) do |remote|
163
+ PeerServer.class_eval do
164
+ def model; SimpleTask end
165
+ def anonymous_model; @anonymous ||= Class.new(model) end
166
+ def check_anonymous_model(remote_model)
167
+ @anonymous == peer.local_object(remote_model)
168
+ end
169
+ end
170
+ end
171
+
172
+ assert_equal(SimpleTask, remote_peer.call(:model).proxy(remote_peer))
173
+
174
+ anonymous = remote_peer.call(:anonymous_model).proxy(remote_peer)
175
+ assert_not_same(anonymous, SimpleTask)
176
+ assert(anonymous < SimpleTask)
177
+ assert(remote_peer.call(:check_anonymous_model, anonymous))
178
+ end
179
+
180
+ def test_marshal_task
181
+ peer2peer(true) do |remote|
182
+ PeerServer.class_eval do
183
+ def task
184
+ plan.insert(@task = Class.new(SimpleTask).new(:id => 1))
185
+ @task.data = [42, @task.class]
186
+ [@task, @task.remote_id]
187
+ end
188
+ def check_sibling(remote_id)
189
+ @task.remote_siblings[peer] == remote_id
190
+ end
191
+ end
192
+ end
193
+
194
+ remote_task, remote_task_id = remote_peer.call(:task)
195
+ assert_kind_of(Task::DRoby, remote_task)
196
+ assert_equal({:id => 1}, remote_task.arguments)
197
+ assert_kind_of(Plan::DRoby, remote_task.plan)
198
+ assert_equal("Roby::Test::SimpleTask", remote_task.model.ancestors[1].first)
199
+ assert_equal([42, remote_task.model], remote_task.data)
200
+ assert_nothing_raised { Marshal.dump(remote_task) }
201
+ assert_equal(remote_task_id, remote_task.remote_siblings[remote_peer.droby_dump(nil)], remote_task.remote_siblings)
202
+ assert(!remote_task.remote_siblings[Roby::Distributed.droby_dump(nil)])
203
+
204
+ plan.permanent(local_proxy = remote_peer.local_object(remote_task))
205
+ assert_kind_of(SimpleTask, local_proxy)
206
+ assert_not_same(SimpleTask, local_proxy.class)
207
+ assert_equal([42, local_proxy.class], local_proxy.data)
208
+
209
+ assert_equal([remote_peer], local_proxy.owners)
210
+ assert_equal(remote_task_id, local_proxy.remote_siblings[remote_peer])
211
+ assert(!local_proxy.read_write?)
212
+ assert( local_proxy.root_object?)
213
+ assert(!local_proxy.event(:start).root_object?)
214
+ remote_peer.synchro_point
215
+ assert(remote_peer.call(:check_sibling, local_proxy.remote_id))
216
+ assert(local_proxy.executable?)
217
+ assert_raises(OwnershipError) { local_proxy.start! }
218
+ end
219
+
220
+ class ErrorWithArguments < Exception
221
+ def initialize(a, b)
222
+ end
223
+ end
224
+
225
+ def test_marshal_exception
226
+ model = Class.new(Exception)
227
+ e = model.exception("test")
228
+
229
+ formatted = Distributed.format(e)
230
+ assert_kind_of(Exception::DRoby, formatted)
231
+ assert_nothing_raised { Marshal.dump(formatted) }
232
+
233
+ peer2peer(true) do |remote|
234
+ def remote.exception
235
+ model = Class.new(Exception)
236
+ e = model.exception("test")
237
+ Distributed.format(e)
238
+ end
239
+
240
+ def remote.exception_with_arguments
241
+ e = begin
242
+ raise ErrorWithArguments.new(1, 2), "test"
243
+ rescue ErrorWithArguments => e
244
+ e
245
+ end
246
+
247
+ Distributed.format(e)
248
+ end
249
+ end
250
+
251
+ m_e = remote.exception
252
+ e = remote_peer.local_object(m_e)
253
+ assert_kind_of(Exception, e)
254
+ assert_not_same(Exception, e.class)
255
+ assert_equal("test", e.message)
256
+
257
+ m_e = remote.exception_with_arguments
258
+ e = remote_peer.local_object(m_e)
259
+ assert_kind_of(Exception, e)
260
+ assert_same(Exception, e.class)
261
+ assert_equal("test (TC_DistributedRobyProtocol::ErrorWithArguments)", e.message)
262
+ end
263
+
264
+ # See #test_local_task_back_forth_through_drb_race_condition
265
+ # This test checks the case where we received the added_sibling message
266
+ def test_local_task_back_forth_through_drb
267
+ peer2peer(true) do |remote|
268
+ PeerServer.class_eval do
269
+ def proxy(object)
270
+ Marshal.dump(object)
271
+ plan.permanent(task = peer.local_object(object))
272
+ task
273
+ end
274
+ end
275
+ end
276
+
277
+ plan.permanent(local_task = SimpleTask.new(:id => 'local'))
278
+ remote_proxy = remote_peer.call(:proxy, local_task)
279
+ remote_peer.synchro_point
280
+ assert(remote_peer.proxies[remote_proxy], [remote_peer.proxies, remote_proxy])
281
+ assert_same(local_task, remote_peer.local_object(remote_proxy), "#{local_task} #{remote_proxy}")
282
+ end
283
+
284
+ # This tests the handling of the following race condition:
285
+ # * we send throught DRb a local object and gets back the marshalled
286
+ # proxy of our remote peer
287
+ # * we get the local object which corresponds to the marshalled
288
+ # object, which should be the original local object
289
+ #
290
+ # The trick here is that, since we disable communication, we call
291
+ # #local_object while the local host does not know yet that the remote host
292
+ # has a sibling for the object
293
+ def test_local_task_back_forth_through_drb_race_condition
294
+ peer2peer(true) do |remote|
295
+ def remote.proxy(object)
296
+ Marshal.dump(object)
297
+ plan.permanent(task = local_peer.local_object(object))
298
+ task
299
+ end
300
+ end
301
+
302
+ begin
303
+ remote.disable_communication
304
+ plan.permanent(local_task = SimpleTask.new(:id => 'local'))
305
+ remote_proxy = remote.proxy(Distributed.format(local_task))
306
+ assert_equal(remote_proxy, remote.proxy(Distributed.format(local_task)))
307
+ assert(!remote_peer.proxies[remote_proxy])
308
+
309
+ ensure
310
+ remote.enable_communication
311
+ end
312
+
313
+ # Test that it is fine to receive the #added_sibling message now
314
+ assert_nothing_raised { remote_peer.synchro_point }
315
+ end
316
+
317
+ # test a particular situations of GC/communication interaction
318
+ # - A finalizes a task T which is owned by B
319
+ # - A receives a message involving T which has been emitted while B was not knowing about the
320
+ # deletion (it has not yet received the removed_sibling message)
321
+ def test_finalized_remote_task_race_condition
322
+ peer2peer(true) do |remote|
323
+ remote.plan.insert(task = SimpleTask.new(:id => 'remote'))
324
+
325
+ remote.singleton_class.class_eval do
326
+ define_method(:send_task_update) do
327
+ task.arguments[:newarg] = 'tested'
328
+ Distributed.format(task)
329
+ end
330
+ end
331
+ end
332
+
333
+ task = remote_task(:id => 'remote') do |task|
334
+ remote_peer.disable_tx
335
+ task
336
+ end
337
+
338
+ Roby.control.wait_one_cycle
339
+ assert(!task.plan)
340
+
341
+ new_task = remote_peer.local_object(remote.send_task_update)
342
+ assert_not_same(task, new_task)
343
+ assert_equal('tested', new_task.arguments[:newarg])
344
+
345
+ ensure
346
+ remote_peer.enable_tx
347
+ end
348
+
349
+ def test_marshal_task_arguments
350
+ peer2peer(true) do |remote|
351
+ PeerServer.class_eval do
352
+ def task
353
+ plan.insert(@task = model.new(:id => 1, :model => model))
354
+ @task
355
+ end
356
+ def model
357
+ @model ||= Class.new(SimpleTask)
358
+ end
359
+ end
360
+ end
361
+ m_model = remote_peer.call(:model)
362
+ m = m_model.proxy(remote_peer)
363
+
364
+ m_task = remote_peer.call(:task)
365
+ assert_nothing_raised { Marshal.dump(m_task) }
366
+ assert_equal(m_model.ancestors, m_task.arguments[:model].ancestors)
367
+ assert_equal(m_model.tags, m_task.arguments[:model].tags)
368
+ t = remote_peer.local_object(m_task)
369
+ assert_equal({ :id => 1, :model => m }, t.arguments)
370
+ end
371
+
372
+ def test_marshal_task_event
373
+ peer2peer(true) do |remote|
374
+ PeerServer.class_eval do
375
+ attr_reader :task
376
+ def task_event
377
+ @task = Class.new(SimpleTask).new(:id => 1)
378
+ task.event(:start)
379
+ end
380
+ end
381
+ end
382
+
383
+ remote_event = remote_peer.call(:task_event)
384
+ assert_nothing_raised { Marshal.dump(remote_event) }
385
+ assert_kind_of(TaskEventGenerator::DRoby, remote_event)
386
+ task = remote_peer.call(:task)
387
+ assert_equal(task.remote_siblings, remote_event.task.remote_siblings)
388
+ assert_equal(remote_peer.local_object(task), remote_peer.local_object(remote_event.task))
389
+ end
390
+
391
+ CommonTaskModelTag = TaskModelTag.new
392
+ def test_marshal_task_model_tag
393
+ peer2peer(true) do |remote|
394
+ PeerServer.class_eval do
395
+ def tag; CommonTaskModelTag end
396
+ def anonymous_tag
397
+ @anonymous ||= TaskModelTag.new do
398
+ include CommonTaskModelTag
399
+ end
400
+ end
401
+ def tagged_task_model
402
+ Class.new(SimpleTask) do
403
+ include CommonTaskModelTag
404
+ end
405
+ end
406
+ def anonymously_tagged_task_model
407
+ tag = anonymous_tag
408
+ Class.new(SimpleTask) do
409
+ include tag
410
+ end
411
+ end
412
+ end
413
+ end
414
+
415
+ Marshal.dump(CommonTaskModelTag)
416
+ assert_equal(CommonTaskModelTag, remote_peer.call(:tag).proxy(remote_peer))
417
+ tagged_task_model = remote_peer.call(:tagged_task_model).proxy(remote_peer)
418
+ assert(tagged_task_model.has_ancestor?(CommonTaskModelTag), tagged_task_model.ancestors)
419
+
420
+ anonymous_tag = remote_peer.call(:anonymous_tag).proxy(remote_peer)
421
+ assert_not_equal(CommonTaskModelTag, anonymous_tag)
422
+ assert(anonymous_tag.has_ancestor?(CommonTaskModelTag), anonymous_tag.ancestors)
423
+ assert_equal(anonymous_tag, remote_peer.call(:anonymous_tag).proxy(remote_peer))
424
+
425
+ tagged_task_model = remote_peer.call(:anonymously_tagged_task_model).proxy(remote_peer)
426
+ assert(tagged_task_model.has_ancestor?(CommonTaskModelTag))
427
+ assert(tagged_task_model.has_ancestor?(anonymous_tag))
428
+ end
429
+
430
+ def test_marshal_event
431
+ peer2peer(true) do |remote|
432
+ remote.plan.insert(t = Task.new)
433
+ t.on(:start, (ev = EventGenerator.new(true)))
434
+ t.event(:start).forward(ev = EventGenerator.new(false))
435
+ t.on(:start, (ev = EventGenerator.new { }))
436
+ PeerServer.class_eval do
437
+ include Test::Unit::Assertions
438
+ define_method(:events) { plan.free_events }
439
+ end
440
+ end
441
+
442
+ marshalled = remote_peer.call(:events)
443
+ marshalled.each { |ev| assert_kind_of(EventGenerator::DRoby, ev) }
444
+
445
+ all_events = marshalled.map { |ev| remote_peer.local_object(ev) }
446
+ assert_equal(1, all_events.find_all { |ev| !ev.controlable? }.size)
447
+ assert_equal(2, all_events.find_all { |ev| ev.controlable? }.size)
448
+ all_events.each do |ev|
449
+ if ev.controlable?
450
+ assert_raises(OwnershipError) { ev.call }
451
+ end
452
+ assert_raises(OwnershipError) { ev.emit }
453
+ end
454
+ end
455
+
456
+ def test_siblings
457
+ peer2peer(true) do |remote|
458
+ plan.insert(Roby::Task.new(:id => 'remote'))
459
+ end
460
+
461
+ plan.insert(remote_task = remote_task(:id => 'remote'))
462
+ assert(remote_task.has_sibling_on?(remote_peer))
463
+ remote_object, _ = remote_peer.proxies.find { |_, task| task == remote_task }
464
+ assert(remote_object)
465
+ assert_equal(remote_object, remote_task.sibling_on(remote_peer))
466
+
467
+ assert_equal(remote_task, remote_task(:id => 'remote'))
468
+ process_events
469
+ assert_equal(remote_task, remote_task(:id => 'remote'))
470
+ end
471
+
472
+
473
+ def test_incremental_dump
474
+ DRb.start_service
475
+ FlexMock.use do |obj|
476
+ obj.should_receive(:droby_dump).and_return([]).once
477
+ FlexMock.use do |destination|
478
+ destination.should_receive(:incremental_dump?).and_return(false).once
479
+ assert_equal([], Distributed.format(obj, destination))
480
+ end
481
+
482
+ obj.should_receive(:remote_id).and_return(Distributed::RemoteID.from_object(obj)).once
483
+ FlexMock.use do |destination|
484
+ destination.should_receive(:incremental_dump?).and_return(true).once
485
+ assert_equal(Distributed::RemoteID.from_object(obj), Distributed.format(obj, destination))
486
+ end
487
+ end
488
+ end
489
+
490
+ def test_local_object
491
+ model = Class.new(Roby::Task) do
492
+ local_only
493
+ end
494
+ task = model.new
495
+ assert(!task.distribute?)
496
+ end
497
+
498
+ def test_dump_sequence
499
+ DRb.start_service
500
+ t1, t2 = prepare_plan :discover => 2
501
+ p = t1+t2
502
+
503
+ formatted = Distributed.format(p)
504
+ assert_nothing_raised(formatted.to_s) { Marshal.dump(formatted) }
505
+ end
506
+
507
+ def test_dump_parallel
508
+ DRb.start_service
509
+ t1, t2 = prepare_plan :discover => 2
510
+ p = t1|t2
511
+
512
+ formatted = Distributed.format(p)
513
+ assert_nothing_raised(formatted.to_s) { Marshal.dump(formatted) }
514
+ end
515
+ end
516
+