roby 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -5
- data/Manifest.txt +91 -16
- data/README.txt +24 -24
- data/Rakefile +92 -64
- data/app/config/app.yml +42 -43
- data/app/config/init.rb +26 -0
- data/benchmark/alloc_misc.rb +123 -0
- data/benchmark/discovery_latency.rb +67 -0
- data/benchmark/garbage_collection.rb +48 -0
- data/benchmark/genom.rb +31 -0
- data/benchmark/transactions.rb +62 -0
- data/bin/roby +1 -1
- data/bin/roby-log +16 -6
- data/doc/guide/.gitignore +2 -0
- data/doc/guide/config.yaml +34 -0
- data/doc/guide/ext/init.rb +14 -0
- data/doc/guide/ext/previous_next.rb +40 -0
- data/doc/guide/ext/rdoc_links.rb +33 -0
- data/doc/guide/index.rdoc +16 -0
- data/doc/guide/overview.rdoc +62 -0
- data/doc/guide/plan_modifications.rdoc +67 -0
- data/doc/guide/src/abstraction/achieve_with.page +8 -0
- data/doc/guide/src/abstraction/forwarding.page +8 -0
- data/doc/guide/src/abstraction/hierarchy.page +19 -0
- data/doc/guide/src/abstraction/index.page +28 -0
- data/doc/guide/src/abstraction/task_models.page +13 -0
- data/doc/guide/src/basics.template +6 -0
- data/doc/guide/src/basics/app.page +139 -0
- data/doc/guide/src/basics/code_examples.page +33 -0
- data/doc/guide/src/basics/dry.page +69 -0
- data/doc/guide/src/basics/errors.page +443 -0
- data/doc/guide/src/basics/events.page +179 -0
- data/doc/guide/src/basics/hierarchy.page +275 -0
- data/doc/guide/src/basics/index.page +11 -0
- data/doc/guide/src/basics/log_replay/goForward_1.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_2.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_3.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_4.png +0 -0
- data/doc/guide/src/basics/log_replay/goForward_5.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_1.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_2.png +0 -0
- data/doc/guide/src/basics/log_replay/hierarchy_error_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_1.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_2.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_3.png +0 -0
- data/doc/guide/src/basics/log_replay/plan_repair_4.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_main_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_log_relation_window.png +0 -0
- data/doc/guide/src/basics/log_replay/roby_replay_event_representation.png +0 -0
- data/doc/guide/src/basics/plan_objects.page +71 -0
- data/doc/guide/src/basics/relations_display.page +203 -0
- data/doc/guide/src/basics/roby_cycle_overview.png +0 -0
- data/doc/guide/src/basics/shell.page +102 -0
- data/doc/guide/src/basics/summary.page +32 -0
- data/doc/guide/src/basics/tasks.page +357 -0
- data/doc/guide/src/basics_shell_header.txt +16 -0
- data/doc/guide/src/cycle/cycle-overview.png +0 -0
- data/doc/guide/src/cycle/cycle-overview.svg +208 -0
- data/doc/guide/src/cycle/error_handling.page +168 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.png +0 -0
- data/doc/guide/src/cycle/error_instantaneous_repair.svg +1224 -0
- data/doc/guide/src/cycle/garbage_collection.page +10 -0
- data/doc/guide/src/cycle/index.page +23 -0
- data/doc/guide/src/cycle/propagation.page +154 -0
- data/doc/guide/src/cycle/propagation_diamond.png +0 -0
- data/doc/guide/src/cycle/propagation_diamond.svg +1279 -0
- data/doc/guide/src/default.css +319 -0
- data/doc/guide/src/default.template +74 -0
- data/doc/guide/src/htmldoc.metainfo +20 -0
- data/doc/guide/src/htmldoc.virtual +18 -0
- data/doc/guide/src/images/bodybg.png +0 -0
- data/doc/guide/src/images/contbg.png +0 -0
- data/doc/guide/src/images/footerbg.png +0 -0
- data/doc/guide/src/images/gradient1.png +0 -0
- data/doc/guide/src/images/gradient2.png +0 -0
- data/doc/guide/src/index.page +7 -0
- data/doc/guide/src/introduction/index.page +29 -0
- data/doc/guide/src/introduction/install.page +133 -0
- data/doc/{papers.rdoc → guide/src/introduction/publications.page} +5 -2
- data/doc/{videos.rdoc → guide/src/introduction/videos.page} +4 -2
- data/doc/guide/src/plugins/fault_tolerance.page +44 -0
- data/doc/guide/src/plugins/index.page +11 -0
- data/doc/guide/src/plugins/subsystems.page +45 -0
- data/doc/guide/src/relations/dependency.page +89 -0
- data/doc/guide/src/relations/index.page +12 -0
- data/doc/misc/update_github +24 -0
- data/doc/tutorials/02-GoForward.rdoc +3 -3
- data/ext/graph/graph.cc +46 -0
- data/lib/roby.rb +57 -22
- data/lib/roby/app.rb +132 -112
- data/lib/roby/app/plugins/rake.rb +21 -0
- data/lib/roby/app/rake.rb +0 -7
- data/lib/roby/app/run.rb +1 -1
- data/lib/roby/app/scripts/distributed.rb +1 -2
- data/lib/roby/app/scripts/generate/bookmarks.rb +1 -1
- data/lib/roby/app/scripts/results.rb +2 -1
- data/lib/roby/app/scripts/run.rb +6 -2
- data/lib/roby/app/scripts/shell.rb +11 -11
- data/lib/roby/config.rb +1 -1
- data/lib/roby/decision_control.rb +62 -3
- data/lib/roby/distributed.rb +4 -0
- data/lib/roby/distributed/base.rb +8 -0
- data/lib/roby/distributed/communication.rb +12 -8
- data/lib/roby/distributed/connection_space.rb +61 -44
- data/lib/roby/distributed/distributed_object.rb +1 -1
- data/lib/roby/distributed/notifications.rb +22 -30
- data/lib/roby/distributed/peer.rb +13 -8
- data/lib/roby/distributed/proxy.rb +5 -5
- data/lib/roby/distributed/subscription.rb +4 -4
- data/lib/roby/distributed/transaction.rb +3 -3
- data/lib/roby/event.rb +176 -110
- data/lib/roby/exceptions.rb +12 -4
- data/lib/roby/execution_engine.rb +1604 -0
- data/lib/roby/external_process_task.rb +225 -0
- data/lib/roby/graph.rb +0 -6
- data/lib/roby/interface.rb +221 -137
- data/lib/roby/log/console.rb +5 -3
- data/lib/roby/log/data_stream.rb +94 -16
- data/lib/roby/log/dot.rb +8 -8
- data/lib/roby/log/event_stream.rb +13 -3
- data/lib/roby/log/file.rb +43 -18
- data/lib/roby/log/gui/basic_display_ui.rb +89 -0
- data/lib/roby/log/gui/chronicle_view_ui.rb +90 -0
- data/lib/roby/log/gui/data_displays.rb +4 -5
- data/lib/roby/log/gui/data_displays_ui.rb +146 -0
- data/lib/roby/log/gui/relations.rb +18 -18
- data/lib/roby/log/gui/relations_ui.rb +120 -0
- data/lib/roby/log/gui/relations_view_ui.rb +144 -0
- data/lib/roby/log/gui/replay.rb +41 -13
- data/lib/roby/log/gui/replay_controls.rb +3 -0
- data/lib/roby/log/gui/replay_controls.ui +133 -110
- data/lib/roby/log/gui/replay_controls_ui.rb +249 -0
- data/lib/roby/log/hooks.rb +19 -18
- data/lib/roby/log/logger.rb +7 -6
- data/lib/roby/log/notifications.rb +4 -4
- data/lib/roby/log/plan_rebuilder.rb +20 -22
- data/lib/roby/log/relations.rb +44 -16
- data/lib/roby/log/server.rb +1 -4
- data/lib/roby/log/timings.rb +88 -19
- data/lib/roby/plan-object.rb +135 -11
- data/lib/roby/plan.rb +408 -224
- data/lib/roby/planning/loops.rb +32 -25
- data/lib/roby/planning/model.rb +157 -51
- data/lib/roby/planning/task.rb +47 -20
- data/lib/roby/query.rb +128 -92
- data/lib/roby/relations.rb +254 -136
- data/lib/roby/relations/conflicts.rb +6 -9
- data/lib/roby/relations/dependency.rb +358 -0
- data/lib/roby/relations/ensured.rb +0 -1
- data/lib/roby/relations/error_handling.rb +0 -1
- data/lib/roby/relations/events.rb +0 -2
- data/lib/roby/relations/executed_by.rb +26 -11
- data/lib/roby/relations/planned_by.rb +14 -14
- data/lib/roby/robot.rb +46 -0
- data/lib/roby/schedulers/basic.rb +34 -0
- data/lib/roby/standalone.rb +4 -0
- data/lib/roby/standard_errors.rb +21 -15
- data/lib/roby/state/events.rb +5 -4
- data/lib/roby/support.rb +107 -6
- data/lib/roby/task-operations.rb +23 -19
- data/lib/roby/task.rb +522 -148
- data/lib/roby/task_index.rb +80 -0
- data/lib/roby/test/common.rb +283 -44
- data/lib/roby/test/distributed.rb +53 -37
- data/lib/roby/test/testcase.rb +9 -204
- data/lib/roby/test/tools.rb +3 -3
- data/lib/roby/transactions.rb +154 -111
- data/lib/roby/transactions/proxy.rb +40 -7
- data/manifest.xml +20 -0
- data/plugins/fault_injection/README.txt +0 -3
- data/plugins/fault_injection/Rakefile +2 -8
- data/plugins/fault_injection/app.rb +1 -1
- data/plugins/fault_injection/fault_injection.rb +3 -3
- data/plugins/fault_injection/test/test_fault_injection.rb +19 -25
- data/plugins/subsystems/README.txt +0 -3
- data/plugins/subsystems/Rakefile +2 -7
- data/plugins/subsystems/app.rb +27 -16
- data/plugins/subsystems/test/app/config/init.rb +3 -0
- data/plugins/subsystems/test/app/planners/main.rb +1 -1
- data/plugins/subsystems/test/app/tasks/services.rb +1 -1
- data/plugins/subsystems/test/test_subsystems.rb +23 -16
- data/test/distributed/test_communication.rb +32 -15
- data/test/distributed/test_connection.rb +28 -26
- data/test/distributed/test_execution.rb +59 -54
- data/test/distributed/test_mixed_plan.rb +34 -34
- data/test/distributed/test_plan_notifications.rb +26 -26
- data/test/distributed/test_protocol.rb +57 -48
- data/test/distributed/test_query.rb +11 -7
- data/test/distributed/test_remote_plan.rb +71 -71
- data/test/distributed/test_transaction.rb +50 -47
- data/test/mockups/external_process +28 -0
- data/test/planning/test_loops.rb +163 -119
- data/test/planning/test_model.rb +3 -3
- data/test/planning/test_task.rb +27 -7
- data/test/relations/test_conflicts.rb +3 -3
- data/test/relations/test_dependency.rb +324 -0
- data/test/relations/test_ensured.rb +2 -2
- data/test/relations/test_executed_by.rb +94 -19
- data/test/relations/test_planned_by.rb +11 -9
- data/test/suite_core.rb +6 -3
- data/test/suite_distributed.rb +1 -0
- data/test/suite_planning.rb +1 -0
- data/test/suite_relations.rb +2 -2
- data/test/tasks/test_external_process.rb +126 -0
- data/test/{test_thread_task.rb → tasks/test_thread_task.rb} +17 -20
- data/test/test_bgl.rb +21 -1
- data/test/test_event.rb +229 -155
- data/test/test_exceptions.rb +79 -80
- data/test/test_execution_engine.rb +987 -0
- data/test/test_gui.rb +1 -1
- data/test/test_interface.rb +11 -5
- data/test/test_log.rb +18 -7
- data/test/test_log_server.rb +1 -0
- data/test/test_plan.rb +229 -395
- data/test/test_query.rb +193 -35
- data/test/test_relations.rb +88 -8
- data/test/test_state.rb +55 -37
- data/test/test_support.rb +1 -1
- data/test/test_task.rb +371 -218
- data/test/test_testcase.rb +32 -16
- data/test/test_transactions.rb +211 -170
- data/test/test_transactions_proxy.rb +37 -19
- metadata +169 -71
- data/.gitignore +0 -29
- data/doc/styles/allison.css +0 -314
- data/doc/styles/allison.js +0 -316
- data/doc/styles/allison.rb +0 -276
- data/doc/styles/jamis.rb +0 -593
- data/lib/roby/control.rb +0 -746
- data/lib/roby/executives/simple.rb +0 -30
- data/lib/roby/propagation.rb +0 -562
- data/lib/roby/relations/hierarchy.rb +0 -239
- data/lib/roby/transactions/updates.rb +0 -139
- data/test/relations/test_hierarchy.rb +0 -158
- data/test/test_control.rb +0 -399
- data/test/test_propagation.rb +0 -210
@@ -0,0 +1,80 @@
|
|
1
|
+
module Roby
|
2
|
+
# TaskIndex objects are used to maintain a set of tasks as classified sets,
|
3
|
+
# speeding up query operations. See Plan#task_index.
|
4
|
+
class TaskIndex
|
5
|
+
# A model => ValueSet map of the tasks for each model
|
6
|
+
attr_reader :by_model
|
7
|
+
# A state => ValueSet map of tasks given their state. The state is
|
8
|
+
# a symbol in [:pending, :starting, :running, :finishing,
|
9
|
+
# :finished]
|
10
|
+
attr_reader :by_state
|
11
|
+
# A peer => ValueSet map of tasks given their owner.
|
12
|
+
attr_reader :by_owner
|
13
|
+
# The set of tasks which have an event which is being repaired
|
14
|
+
attr_reader :repaired_tasks
|
15
|
+
|
16
|
+
STATE_PREDICATES = [:pending?, :running?, :finished?, :success?, :failed?].to_value_set
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@by_model = Hash.new { |h, k| h[k] = ValueSet.new }
|
20
|
+
@by_state = Hash.new
|
21
|
+
STATE_PREDICATES.each do |state_name|
|
22
|
+
by_state[state_name] = ValueSet.new
|
23
|
+
end
|
24
|
+
@by_owner = Hash.new
|
25
|
+
@task_state = Hash.new
|
26
|
+
@repaired_tasks = ValueSet.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add a new task to this index
|
30
|
+
def add(task)
|
31
|
+
for klass in task.model.ancestors
|
32
|
+
by_model[klass] << task
|
33
|
+
end
|
34
|
+
by_state[:pending?] << task
|
35
|
+
for owner in task.owners
|
36
|
+
add_owner(task, owner)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Updates the index to reflect that +new_owner+ now owns +task+
|
41
|
+
def add_owner(task, new_owner)
|
42
|
+
(by_owner[new_owner] ||= ValueSet.new) << task
|
43
|
+
end
|
44
|
+
|
45
|
+
# Updates the index to reflect that +peer+ no more owns +task+
|
46
|
+
def remove_owner(task, peer)
|
47
|
+
if set = by_owner[peer]
|
48
|
+
set.delete(task)
|
49
|
+
if set.empty?
|
50
|
+
by_owner.delete(peer)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Updates the index to reflect a change of state for +task+
|
56
|
+
def set_state(task, new_state)
|
57
|
+
for state_set in by_state
|
58
|
+
state_set.last.delete(task)
|
59
|
+
end
|
60
|
+
by_state[new_state] << task
|
61
|
+
if new_state == :success? || new_state == :failed?
|
62
|
+
by_state[:finished?] << task
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Remove all references of +task+ from the index.
|
67
|
+
def remove(task)
|
68
|
+
for klass in task.model.ancestors
|
69
|
+
by_model[klass].delete(task)
|
70
|
+
end
|
71
|
+
for state_set in by_state
|
72
|
+
state_set.last.delete(task)
|
73
|
+
end
|
74
|
+
for owner in task.owners
|
75
|
+
remove_owner(task, owner)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
data/lib/roby/test/common.rb
CHANGED
@@ -22,14 +22,24 @@ module Roby
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# The plan used by the tests
|
25
|
-
|
25
|
+
attr_reader :plan
|
26
|
+
# The decision control component used by the tests
|
27
|
+
attr_reader :control
|
28
|
+
def engine; plan.engine end
|
26
29
|
|
27
30
|
# Clear the plan and return it
|
28
31
|
def new_plan
|
29
|
-
|
32
|
+
plan.clear
|
30
33
|
plan
|
31
34
|
end
|
32
35
|
|
36
|
+
def deprecated_feature
|
37
|
+
Roby.enable_deprecation_warnings = false
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
Roby.enable_deprecation_warnings = true
|
41
|
+
end
|
42
|
+
|
33
43
|
# a [collection, collection_backup] array of the collections saved
|
34
44
|
# by #original_collections
|
35
45
|
attr_reader :original_collections
|
@@ -54,18 +64,25 @@ module Roby
|
|
54
64
|
end
|
55
65
|
|
56
66
|
def setup
|
67
|
+
super if defined? super
|
68
|
+
|
57
69
|
@console_logger ||= false
|
70
|
+
@event_logger ||= false
|
58
71
|
if !defined? Roby::State
|
59
|
-
|
72
|
+
Roby.const_set(:State, StateSpace.new)
|
73
|
+
else
|
74
|
+
Roby::State.clear
|
60
75
|
end
|
61
76
|
|
62
77
|
@original_roby_logger_level = Roby.logger.level
|
63
78
|
@timings = { :start => Time.now }
|
64
79
|
|
65
80
|
@original_collections = []
|
66
|
-
Thread.abort_on_exception =
|
81
|
+
Thread.abort_on_exception = false
|
67
82
|
@remote_processes = []
|
68
83
|
|
84
|
+
Roby.app.setup_loggers
|
85
|
+
|
69
86
|
if Test.check_allocation_count
|
70
87
|
GC.start
|
71
88
|
GC.disable
|
@@ -79,34 +96,48 @@ module Roby
|
|
79
96
|
Roby::Planning::Planner.last_id = 0
|
80
97
|
end
|
81
98
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
Roby.control.abort_on_application_exception = true
|
89
|
-
Roby.control.abort_on_framework_exception = true
|
99
|
+
@plan ||= Plan.new
|
100
|
+
@control ||= DecisionControl.new
|
101
|
+
if !plan.engine
|
102
|
+
ExecutionEngine.new(@plan, @control)
|
103
|
+
end
|
104
|
+
plan.engine.gc_warning = false
|
90
105
|
|
91
|
-
|
92
|
-
save_collection
|
106
|
+
# Save and restore some arrays
|
107
|
+
save_collection engine.propagation_handlers
|
108
|
+
save_collection Roby::ExecutionEngine.propagation_handlers
|
109
|
+
save_collection plan.structure_checks
|
110
|
+
save_collection Roby::Plan.structure_checks
|
111
|
+
save_collection engine.at_cycle_end_handlers
|
112
|
+
save_collection Roby::EventGenerator.event_gathering
|
113
|
+
Roby.app.abort_on_exception = true
|
114
|
+
Roby.app.abort_on_application_exception = true
|
93
115
|
|
94
|
-
save_collection
|
116
|
+
save_collection engine.event_ordering
|
117
|
+
save_collection engine.delayed_events
|
118
|
+
save_collection plan.exception_handlers
|
95
119
|
timings[:setup] = Time.now
|
120
|
+
|
121
|
+
engine.at_cycle_end(&Test.method(:check_event_assertions))
|
122
|
+
engine.finalizers << Test.method(:finalize_event_assertions)
|
96
123
|
end
|
97
124
|
|
125
|
+
|
98
126
|
def teardown_plan
|
127
|
+
engine.at_cycle_end_handlers.delete(Test.method(:check_event_assertions))
|
128
|
+
engine.finalizers.delete(Test.method(:finalize_event_assertions))
|
129
|
+
|
99
130
|
old_gc_roby_logger_level = Roby.logger.level
|
100
131
|
if debug_gc?
|
101
132
|
Roby.logger.level = Logger::DEBUG
|
102
133
|
end
|
103
134
|
|
104
|
-
if !
|
105
|
-
|
135
|
+
if !engine.running?
|
136
|
+
engine.run
|
106
137
|
end
|
107
138
|
|
108
|
-
|
109
|
-
|
139
|
+
engine.quit
|
140
|
+
engine.join
|
110
141
|
plan.clear
|
111
142
|
|
112
143
|
ensure
|
@@ -142,10 +173,9 @@ module Roby
|
|
142
173
|
end
|
143
174
|
|
144
175
|
Roby::TaskStructure::Hierarchy.interesting_events.clear
|
145
|
-
if defined? Roby::
|
146
|
-
Roby.
|
147
|
-
Roby.
|
148
|
-
Roby.control.abort_on_framework_exception = false
|
176
|
+
if defined? Roby::Application
|
177
|
+
Roby.app.abort_on_exception = false
|
178
|
+
Roby.app.abort_on_application_exception = false
|
149
179
|
end
|
150
180
|
|
151
181
|
if defined? Roby::Log
|
@@ -169,24 +199,28 @@ module Roby
|
|
169
199
|
end
|
170
200
|
end
|
171
201
|
|
202
|
+
super if defined? super
|
203
|
+
|
172
204
|
rescue Exception => e
|
173
205
|
STDERR.puts "failed teardown: #{e.full_message}"
|
174
206
|
|
175
207
|
ensure
|
176
|
-
while
|
177
|
-
|
178
|
-
|
208
|
+
while engine.running?
|
209
|
+
engine.quit
|
210
|
+
engine.join rescue nil
|
179
211
|
end
|
180
|
-
|
212
|
+
plan.clear
|
213
|
+
@plan = nil
|
181
214
|
|
182
215
|
Roby.logger.level = @original_roby_logger_level
|
183
216
|
self.console_logger = false
|
217
|
+
self.event_logger = false
|
184
218
|
end
|
185
219
|
|
186
220
|
# Process pending events
|
187
221
|
def process_events
|
188
|
-
Roby
|
189
|
-
|
222
|
+
Roby.synchronize do
|
223
|
+
engine.process_events
|
190
224
|
end
|
191
225
|
end
|
192
226
|
|
@@ -215,29 +249,29 @@ module Roby
|
|
215
249
|
#
|
216
250
|
def prepare_plan(options)
|
217
251
|
options = validate_options options,
|
218
|
-
:missions => 0, :discover => 0, :tasks => 0,
|
252
|
+
:missions => 0, :add => 0, :discover => 0, :tasks => 0,
|
219
253
|
:permanent => 0,
|
220
254
|
:model => Roby::Task, :plan => plan
|
221
255
|
|
222
|
-
missions, permanent,
|
256
|
+
missions, permanent, added, tasks = [], [], [], []
|
223
257
|
(1..options[:missions]).each do |i|
|
224
|
-
options[:plan].
|
258
|
+
options[:plan].add_mission(t = options[:model].new(:id => "mission-#{i}"))
|
225
259
|
missions << t
|
226
260
|
end
|
227
261
|
(1..options[:permanent]).each do |i|
|
228
|
-
options[:plan].
|
262
|
+
options[:plan].add_permanent(t = options[:model].new(:id => "perm-#{i}"))
|
229
263
|
permanent << t
|
230
264
|
end
|
231
|
-
(1..options[:discover]).each do |i|
|
232
|
-
options[:plan].
|
233
|
-
|
265
|
+
(1..(options[:discover] + options[:add])).each do |i|
|
266
|
+
options[:plan].add(t = options[:model].new(:id => "discover-#{i}"))
|
267
|
+
added << t
|
234
268
|
end
|
235
269
|
(1..options[:tasks]).each do |i|
|
236
270
|
tasks << options[:model].new(:id => "task-#{i}")
|
237
271
|
end
|
238
272
|
|
239
273
|
result = []
|
240
|
-
[missions, permanent,
|
274
|
+
[missions, permanent, added, tasks].each do |set|
|
241
275
|
unless set.empty?
|
242
276
|
set = *set
|
243
277
|
result << set
|
@@ -255,19 +289,24 @@ module Roby
|
|
255
289
|
start_r, start_w= IO.pipe
|
256
290
|
quit_r, quit_w = IO.pipe
|
257
291
|
remote_pid = fork do
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
292
|
+
begin
|
293
|
+
start_r.close
|
294
|
+
yield
|
295
|
+
rescue Exception => e
|
296
|
+
puts e.full_message
|
297
|
+
end
|
298
|
+
|
299
|
+
start_w.write('OK')
|
300
|
+
quit_r.read(2)
|
262
301
|
end
|
263
302
|
start_w.close
|
264
|
-
start_r.read(2)
|
303
|
+
result = start_r.read(2)
|
265
304
|
|
266
305
|
remote_processes << [remote_pid, quit_w]
|
267
306
|
remote_pid
|
268
307
|
|
269
308
|
ensure
|
270
|
-
start_r.close
|
309
|
+
# start_r.close
|
271
310
|
end
|
272
311
|
|
273
312
|
# Stop all the remote processes that have been started using #remote_process
|
@@ -295,7 +334,8 @@ module Roby
|
|
295
334
|
assert_nothing_raised do
|
296
335
|
begin
|
297
336
|
yield
|
298
|
-
rescue
|
337
|
+
rescue Exception => e
|
338
|
+
assert_kind_of(localized_error_type, e)
|
299
339
|
assert_respond_to(e, :error)
|
300
340
|
assert_kind_of(klass, e.error)
|
301
341
|
end
|
@@ -372,6 +412,21 @@ module Roby
|
|
372
412
|
end
|
373
413
|
end
|
374
414
|
|
415
|
+
attr_reader :event_logger
|
416
|
+
def event_logger=(value)
|
417
|
+
if value && !@event_logger
|
418
|
+
require 'roby/log/file'
|
419
|
+
logfile = @method_name + ".log"
|
420
|
+
logger = Roby::Log::FileLogger.new(logfile)
|
421
|
+
logger.stats_mode = false
|
422
|
+
Roby::Log.add_logger logger
|
423
|
+
@event_logger = logger
|
424
|
+
elsif !value && @event_logger
|
425
|
+
Roby::Log.remove_logger @event_logger
|
426
|
+
@event_logger = nil
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
375
430
|
def wait_thread_stopped(thread)
|
376
431
|
while !thread.stop?
|
377
432
|
sleep(0.1)
|
@@ -394,6 +449,190 @@ module Roby
|
|
394
449
|
|
395
450
|
result
|
396
451
|
end
|
452
|
+
|
453
|
+
@event_assertions = []
|
454
|
+
@waiting_threads = []
|
455
|
+
|
456
|
+
ASSERT_ANY_EVENTS_TLS = :assert_any_events
|
457
|
+
|
458
|
+
class << self
|
459
|
+
# A [thread, cv, positive, negative] list of event assertions
|
460
|
+
attr_reader :event_assertions
|
461
|
+
end
|
462
|
+
|
463
|
+
# Tests for events in +positive+ and +negative+ and returns
|
464
|
+
# the set of failing events if the assertion has finished.
|
465
|
+
# If the set is empty, it means that the assertion finished
|
466
|
+
# successfully
|
467
|
+
def self.assert_any_event_result(positive, negative)
|
468
|
+
if positive_ev = positive.find { |ev| ev.happened? }
|
469
|
+
return false, "#{positive_ev} happened"
|
470
|
+
end
|
471
|
+
failure = negative.find_all { |ev| ev.happened? }
|
472
|
+
unless failure.empty?
|
473
|
+
return true, "#{failure} happened"
|
474
|
+
end
|
475
|
+
|
476
|
+
if positive.all? { |ev| ev.unreachable? }
|
477
|
+
positive.each do |ev|
|
478
|
+
Robot.info "#{ev} is unreachable because of the following emission:"
|
479
|
+
Roby.log_exception(ev.unreachability_reason, Robot.logger, :info)
|
480
|
+
end
|
481
|
+
return true, "all positive events are unreachable"
|
482
|
+
end
|
483
|
+
|
484
|
+
nil
|
485
|
+
end
|
486
|
+
|
487
|
+
# This method is inserted in the control thread to implement
|
488
|
+
# Assertions#assert_events
|
489
|
+
def self.check_event_assertions
|
490
|
+
event_assertions.delete_if do |thread, cv, positive, negative|
|
491
|
+
error, result = Test.assert_any_event_result(positive, negative)
|
492
|
+
if !error.nil?
|
493
|
+
thread[ASSERT_ANY_EVENTS_TLS] = [error, result]
|
494
|
+
cv.broadcast
|
495
|
+
true
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def self.finalize_event_assertions
|
501
|
+
check_event_assertions
|
502
|
+
event_assertions.dup.each do |thread, *_|
|
503
|
+
thread.raise ControlQuitError
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
module Assertions
|
508
|
+
# Wait for any event in +positive+ to happen. If +negative+ is
|
509
|
+
# non-empty, any event happening in this set will make the
|
510
|
+
# assertion fail. If events in +positive+ are task events, the
|
511
|
+
# :stop events of the corresponding tasks are added to negative
|
512
|
+
# automatically.
|
513
|
+
#
|
514
|
+
# If a block is given, it is called from within the control thread
|
515
|
+
# after the checks are in place
|
516
|
+
#
|
517
|
+
# So, to check that a task fails, do
|
518
|
+
#
|
519
|
+
# assert_events(task.event(:fail)) do
|
520
|
+
# task.start!
|
521
|
+
# end
|
522
|
+
#
|
523
|
+
def assert_any_event(positive, negative = [], msg = nil, &block)
|
524
|
+
control_priority do
|
525
|
+
engine.waiting_threads << Thread.current
|
526
|
+
Roby.condition_variable(false) do |cv|
|
527
|
+
positive = Array[*positive].to_value_set
|
528
|
+
negative = Array[*negative].to_value_set
|
529
|
+
|
530
|
+
unreachability_reason = ValueSet.new
|
531
|
+
Roby.synchronize do
|
532
|
+
positive.each do |ev|
|
533
|
+
ev.if_unreachable(true) do |reason|
|
534
|
+
unreachability_reason << reason if reason
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
error, result = Test.assert_any_event_result(positive, negative)
|
539
|
+
if error.nil?
|
540
|
+
this_thread = Thread.current
|
541
|
+
|
542
|
+
Test.event_assertions << [this_thread, cv, positive, negative]
|
543
|
+
engine.once(&block) if block_given?
|
544
|
+
begin
|
545
|
+
cv.wait(Roby.global_lock)
|
546
|
+
ensure
|
547
|
+
Test.event_assertions.delete_if { |thread, _| thread == this_thread }
|
548
|
+
end
|
549
|
+
|
550
|
+
error, result = this_thread[ASSERT_ANY_EVENTS_TLS]
|
551
|
+
end
|
552
|
+
|
553
|
+
if error
|
554
|
+
if !unreachability_reason.empty?
|
555
|
+
msg = unreachability_reason.map do |reason|
|
556
|
+
if reason.respond_to?(:context)
|
557
|
+
context = (reason.context || []).map do |obj|
|
558
|
+
if obj.kind_of?(Exception)
|
559
|
+
obj.full_message
|
560
|
+
else
|
561
|
+
obj.to_s
|
562
|
+
end
|
563
|
+
end
|
564
|
+
reason.to_s + context.join("\n ")
|
565
|
+
end
|
566
|
+
end
|
567
|
+
msg.join("\n ")
|
568
|
+
|
569
|
+
flunk("#{msg} all positive events are unreachable for the following reason:\n #{msg}")
|
570
|
+
elsif msg
|
571
|
+
flunk("#{msg} failed: #{result}")
|
572
|
+
else
|
573
|
+
flunk(result)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
end
|
579
|
+
ensure
|
580
|
+
engine.waiting_threads.delete(Thread.current)
|
581
|
+
end
|
582
|
+
|
583
|
+
# Starts +task+ and checks it succeeds
|
584
|
+
def assert_succeeds(task, *args)
|
585
|
+
control_priority do
|
586
|
+
if !task.kind_of?(Roby::Task)
|
587
|
+
engine.execute do
|
588
|
+
plan.add_mission(task = planner.send(task, *args))
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
assert_any_event([task.event(:success)], [], nil) do
|
593
|
+
plan.add_permanent(task)
|
594
|
+
task.start! if task.pending?
|
595
|
+
yield if block_given?
|
596
|
+
end
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
def control_priority
|
601
|
+
if !engine.thread
|
602
|
+
return yield
|
603
|
+
end
|
604
|
+
|
605
|
+
old_priority = Thread.current.priority
|
606
|
+
Thread.current.priority = engine.thread.priority + 1
|
607
|
+
|
608
|
+
yield
|
609
|
+
ensure
|
610
|
+
Thread.current.priority = old_priority if old_priority
|
611
|
+
end
|
612
|
+
|
613
|
+
# This assertion fails if the relative error between +found+ and
|
614
|
+
# +expected+is more than +error+
|
615
|
+
def assert_relative_error(expected, found, error, msg = "")
|
616
|
+
if expected == 0
|
617
|
+
assert_in_delta(0, found, error, "comparing #{found} to #{expected} in #{msg}")
|
618
|
+
else
|
619
|
+
assert_in_delta(0, (found - expected) / expected, error, "comparing #{found} to #{expected} in #{msg}")
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
# This assertion fails if +found+ and +expected+ are more than +dl+
|
624
|
+
# meters apart in the x, y and z coordinates, or +dt+ radians apart
|
625
|
+
# in angles
|
626
|
+
def assert_same_position(expected, found, dl = 0.01, dt = 0.01, msg = "")
|
627
|
+
assert_relative_error(expected.x, found.x, dl, msg)
|
628
|
+
assert_relative_error(expected.y, found.y, dl, msg)
|
629
|
+
assert_relative_error(expected.z, found.z, dl, msg)
|
630
|
+
assert_relative_error(expected.yaw, found.yaw, dt, msg)
|
631
|
+
assert_relative_error(expected.pitch, found.pitch, dt, msg)
|
632
|
+
assert_relative_error(expected.roll, found.roll, dt, msg)
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
397
636
|
end
|
398
637
|
end
|
399
638
|
|