tap 0.8.0 → 0.9.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.
- data/Basic Overview +151 -0
- data/Command Reference +99 -0
- data/History +24 -0
- data/MIT-LICENSE +1 -1
- data/README +29 -57
- data/Rakefile +30 -37
- data/Tutorial +243 -191
- data/bin/tap +66 -35
- data/lib/tap.rb +47 -29
- data/lib/tap/app.rb +700 -342
- data/lib/tap/{script → cmd}/console.rb +0 -0
- data/lib/tap/{script → cmd}/destroy.rb +0 -0
- data/lib/tap/{script → cmd}/generate.rb +0 -0
- data/lib/tap/cmd/run.rb +156 -0
- data/lib/tap/constants.rb +4 -0
- data/lib/tap/dump.rb +57 -0
- data/lib/tap/env.rb +316 -0
- data/lib/tap/file_task.rb +106 -109
- data/lib/tap/generator.rb +4 -1
- data/lib/tap/generator/generators/command/USAGE +6 -0
- data/lib/tap/generator/generators/command/command_generator.rb +17 -0
- data/lib/tap/generator/generators/{script/templates/script.erb → command/templates/command.erb} +10 -10
- data/lib/tap/generator/generators/config/USAGE +21 -0
- data/lib/tap/generator/generators/config/config_generator.rb +17 -7
- data/lib/tap/generator/generators/file_task/USAGE +3 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -0
- data/lib/tap/generator/generators/file_task/templates/file.txt +2 -0
- data/lib/tap/generator/generators/file_task/templates/file.yml +3 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +26 -20
- data/lib/tap/generator/generators/file_task/templates/test.erb +20 -10
- data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
- data/lib/tap/generator/generators/generator/templates/generator.erb +21 -12
- data/lib/tap/generator/generators/root/templates/Rakefile +33 -24
- data/lib/tap/generator/generators/root/templates/tap.yml +28 -31
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +1 -0
- data/lib/tap/generator/generators/task/USAGE +3 -0
- data/lib/tap/generator/generators/task/task_generator.rb +18 -5
- data/lib/tap/generator/generators/task/templates/task.erb +7 -12
- data/lib/tap/generator/generators/task/templates/test.erb +10 -11
- data/lib/tap/generator/generators/workflow/templates/task.erb +1 -1
- data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
- data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
- data/lib/tap/patches/rake/testtask.rb +55 -0
- data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
- data/lib/tap/patches/ruby19/parsedate.rb +16 -0
- data/lib/tap/root.rb +172 -67
- data/lib/tap/script.rb +70 -336
- data/lib/tap/support/aggregator.rb +55 -0
- data/lib/tap/support/audit.rb +281 -280
- data/lib/tap/support/batchable.rb +59 -0
- data/lib/tap/support/class_configuration.rb +279 -0
- data/lib/tap/support/configurable.rb +92 -0
- data/lib/tap/support/configurable_methods.rb +296 -0
- data/lib/tap/support/executable.rb +98 -0
- data/lib/tap/support/executable_queue.rb +82 -0
- data/lib/tap/support/logger.rb +9 -15
- data/lib/tap/support/rake.rb +43 -54
- data/lib/tap/support/run_error.rb +32 -13
- data/lib/tap/support/shell_utils.rb +47 -0
- data/lib/tap/support/tdoc.rb +9 -8
- data/lib/tap/support/tdoc/config_attr.rb +40 -16
- data/lib/tap/support/validation.rb +77 -0
- data/lib/tap/support/versions.rb +36 -36
- data/lib/tap/task.rb +276 -482
- data/lib/tap/test.rb +20 -261
- data/lib/tap/test/env_vars.rb +7 -5
- data/lib/tap/test/file_methods.rb +126 -121
- data/lib/tap/test/subset_methods.rb +86 -45
- data/lib/tap/test/tap_methods.rb +271 -0
- data/lib/tap/workflow.rb +174 -46
- data/test/app/config/another/task.yml +1 -0
- data/test/app/config/erb.yml +2 -1
- data/test/app/config/some/task.yml +1 -0
- data/test/app/config/template.yml +2 -6
- data/test/app_test.rb +1241 -1008
- data/test/env/test_configure/recurse_a.yml +2 -0
- data/test/env/test_configure/recurse_b.yml +2 -0
- data/test/env/test_configure/tap.yml +23 -0
- data/test/env/test_load_env_config/dir/tap.yml +3 -0
- data/test/env/test_load_env_config/recurse_a.yml +2 -0
- data/test/env/test_load_env_config/recurse_b.yml +2 -0
- data/test/env/test_load_env_config/tap.yml +3 -0
- data/test/env_test.rb +198 -0
- data/test/file_task_test.rb +70 -53
- data/{lib/tap/generator/generators/package/USAGE → test/root/file.txt} +0 -0
- data/test/root_test.rb +621 -454
- data/test/script_test.rb +38 -174
- data/test/support/aggregator_test.rb +99 -0
- data/test/support/audit_test.rb +409 -416
- data/test/support/batchable_test.rb +74 -0
- data/test/support/{task_configuration_test.rb → class_configuration_test.rb} +106 -47
- data/test/{task/config/overriding.yml → support/configurable/config/configured.yml} +0 -0
- data/test/support/configurable_test.rb +295 -0
- data/test/support/executable_queue_test.rb +103 -0
- data/test/support/executable_test.rb +38 -0
- data/test/support/logger_test.rb +17 -17
- data/test/support/rake_test.rb +4 -2
- data/test/support/shell_utils_test.rb +24 -0
- data/test/support/tdoc_test.rb +265 -258
- data/test/support/validation_test.rb +54 -0
- data/test/support/versions_test.rb +38 -38
- data/test/tap_test_helper.rb +19 -5
- data/test/tap_test_suite.rb +5 -2
- data/test/task_base_test.rb +13 -104
- data/test/task_syntax_test.rb +300 -0
- data/test/task_test.rb +258 -381
- data/test/test/env_vars_test.rb +40 -40
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/two.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/two.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/one.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_different_content}/expected/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_missing_expected_file}/expected/one.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/two.txt +1 -0
- data/test/test/file_methods_doc_test.rb +29 -0
- data/test/test/file_methods_test.rb +214 -143
- data/test/test/subset_methods_test.rb +111 -115
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/b.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/b.txt +0 -0
- data/test/test/tap_methods_test.rb +399 -0
- data/test/workflow_test.rb +101 -91
- metadata +86 -70
- data/lib/tap/generator/generators/package/package_generator.rb +0 -38
- data/lib/tap/generator/generators/package/templates/package.erb +0 -186
- data/lib/tap/generator/generators/script/USAGE +0 -0
- data/lib/tap/generator/generators/script/script_generator.rb +0 -17
- data/lib/tap/script/run.rb +0 -154
- data/lib/tap/support/batch_queue.rb +0 -162
- data/lib/tap/support/combinator.rb +0 -114
- data/lib/tap/support/task_configuration.rb +0 -169
- data/lib/tap/support/template.rb +0 -81
- data/lib/tap/support/templater.rb +0 -155
- data/lib/tap/version.rb +0 -4
- data/test/app/config/addition_template.yml +0 -6
- data/test/app_class_test.rb +0 -33
- data/test/check/binding_eval.rb +0 -23
- data/test/check/define_method_check.rb +0 -22
- data/test/check/dependencies_check.rb +0 -175
- data/test/check/inheritance_check.rb +0 -22
- data/test/support/batch_queue_test.rb +0 -320
- data/test/support/combinator_test.rb +0 -249
- data/test/support/template_test.rb +0 -122
- data/test/support/templater/erb.txt +0 -2
- data/test/support/templater/erb.yml +0 -2
- data/test/support/templater/somefile.txt +0 -2
- data/test/support/templater_test.rb +0 -192
- data/test/task/config/template.yml +0 -4
- data/test/task_class_test.rb +0 -170
- data/test/task_execute_test.rb +0 -262
- data/test/test/file_methods/test_assert_expected/expected/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/expected/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
- data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
- data/test/test/file_methods/test_file_compare/expected/output_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/expected/output_2.txt +0 -1
- data/test/test/file_methods/test_file_compare/input/input_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/input/input_2.txt +0 -3
- data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
- data/test/test/file_methods/test_yml_compare/expected/output_1.yml +0 -6
- data/test/test/file_methods/test_yml_compare/expected/output_2.yml +0 -6
- data/test/test/file_methods/test_yml_compare/input/input_1.yml +0 -4
- data/test/test/file_methods/test_yml_compare/input/input_2.yml +0 -4
- data/test/test_test.rb +0 -373
data/lib/tap/workflow.rb
CHANGED
|
@@ -1,75 +1,203 @@
|
|
|
1
1
|
module Tap
|
|
2
2
|
|
|
3
|
-
# ==
|
|
3
|
+
# == Overview
|
|
4
4
|
#
|
|
5
5
|
# App can build workflows directly, using methods like sequence, merge, and
|
|
6
6
|
# multithread, but these workflows are hard to abstract and resuse. Workflow
|
|
7
7
|
# is a specialized type of Task allows the encapsulation and reuse of workflow
|
|
8
|
-
# logic.
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
8
|
+
# logic. See Tap::Task for the shared documentation.
|
|
9
|
+
#
|
|
10
|
+
# === Workflow Definition
|
|
11
|
+
#
|
|
12
|
+
# During initialization, Workflow executes the workflow method (by default the
|
|
13
|
+
# block provided to Workflow.new) to define the workflow logic. This method
|
|
14
|
+
# defines one or more entry_points and zero or more exit points, as well as
|
|
15
|
+
# the internal logic for the workflow.
|
|
16
|
+
#
|
|
17
|
+
# Workflow.new do |w|
|
|
18
|
+
# factor = w.config[:factor] || 1
|
|
19
|
+
#
|
|
20
|
+
# t1 = Task.new {|task, input| input += 1 }
|
|
21
|
+
# t2 = Task.new {|task, input| input += 10 }
|
|
22
|
+
# t3 = Task.new {|task, input| input *= factor }
|
|
23
|
+
#
|
|
24
|
+
# w.app.sequence(t1, t2, t3)
|
|
25
|
+
# w.entry_point = t1
|
|
26
|
+
# w.exit_point = t3
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# Or equivalently:
|
|
30
|
+
#
|
|
31
|
+
# class SimpleSequence < Workflow
|
|
32
|
+
# config :factor, 1
|
|
33
|
+
#
|
|
34
|
+
# def workflow
|
|
35
|
+
# t1 = Task.new {|task, input| input += 5 }
|
|
36
|
+
# t2 = Task.new {|task, input| input += 3 }
|
|
37
|
+
# t3 = Task.new {|task, input| input *= factor }
|
|
38
|
+
#
|
|
39
|
+
# app.sequence(t1, t2, t3)
|
|
40
|
+
# self.entry_point = t1
|
|
41
|
+
# self.exit_point = t3
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# To facilitate the specification of entry and exit points, workflow
|
|
46
|
+
# can accomodate either single-task assignments or a collection. By
|
|
47
|
+
# default both are hashes, but they can be reassigned:
|
|
20
48
|
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
# Workflow.new do |w|
|
|
50
|
+
# w.entry_point.class # => Hash
|
|
51
|
+
# w.exit_point.class # => Hash
|
|
52
|
+
# w.entry_point[:main] = Task.new
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# Workflow.new {|w| w.entry_point = Task.new }
|
|
56
|
+
# Workflow.new {|w| w.entry_point = [Task.new, Task.new] }
|
|
57
|
+
#
|
|
58
|
+
# Access to the group of entry/exit points is standardized to an
|
|
59
|
+
# array via the entry_points and exit_points methods.
|
|
60
|
+
#
|
|
61
|
+
# === Workflow Behavior
|
|
62
|
+
#
|
|
63
|
+
# The entry points act as an enque batch; when the workflow is enqued, the
|
|
64
|
+
# entry points are enqued. The exit points act as an on_complete batch; their
|
|
65
|
+
# on_complete blocks are set for workflow.on_complete.
|
|
66
|
+
#
|
|
67
|
+
# w = SimpleSequence.new
|
|
68
|
+
# w.enq(0)
|
|
69
|
+
# app.run
|
|
70
|
+
# app.results(w.exit_points) # => [8]
|
|
71
|
+
#
|
|
72
|
+
# The batching of entry and exit points is distinct from workflow.batch itself.
|
|
73
|
+
# Workflows can be batched like Tasks, such that all entry points from all
|
|
74
|
+
# workflows in a batch are enqued at once.
|
|
75
|
+
#
|
|
76
|
+
# w1 = SimpleSequence.new nil, :factor => 1
|
|
77
|
+
# w2 = w1.initialize_batch_obj nil, :factor => -1
|
|
78
|
+
#
|
|
79
|
+
# w1.enq(0)
|
|
80
|
+
# app.run
|
|
81
|
+
# app.results(w1.exit_points, w2.exit_points)) # => [8, -8]
|
|
82
|
+
#
|
|
83
|
+
class Workflow
|
|
84
|
+
include Support::Configurable
|
|
85
|
+
|
|
86
|
+
# The entry point for self.
|
|
87
|
+
attr_accessor :entry_point
|
|
88
|
+
|
|
89
|
+
# The exit point for self.
|
|
90
|
+
attr_accessor :exit_point
|
|
91
|
+
|
|
92
|
+
# The task block provided during initialization.
|
|
93
|
+
attr_reader :task_block
|
|
94
|
+
|
|
95
|
+
# Creates a new Task with the specified attributes.
|
|
96
|
+
def initialize(name=nil, config={}, app=App.instance, &task_block)
|
|
97
|
+
@task_block = (task_block == nil ? default_task_block : task_block)
|
|
98
|
+
super(name, config, app)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Initializes a new batch object, running workflow to set the
|
|
102
|
+
# instance-specific entry/exit points. Raises an error if
|
|
103
|
+
# no entry points are defined.
|
|
104
|
+
def initialize_batch_obj(name=nil, config={})
|
|
105
|
+
task = super(name, config)
|
|
106
|
+
|
|
107
|
+
task.entry_point = {}
|
|
108
|
+
task.exit_point = {}
|
|
109
|
+
task.workflow
|
|
34
110
|
|
|
35
|
-
|
|
36
|
-
self.exit_point = {}
|
|
37
|
-
self.workflow
|
|
111
|
+
raise WorkflowError.new("No entry points defined") if task.entry_points.empty?
|
|
38
112
|
|
|
113
|
+
task
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns an array of entry points, determined from entry_point.
|
|
117
|
+
def entry_points
|
|
39
118
|
case entry_point
|
|
40
|
-
when Hash
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
fork(self, *targets)
|
|
44
|
-
when Task
|
|
45
|
-
sequence(self, entry_point)
|
|
119
|
+
when Hash then entry_point.values
|
|
120
|
+
when Support::Executable then [entry_point]
|
|
121
|
+
when Array then entry_point
|
|
46
122
|
else
|
|
47
|
-
raise
|
|
123
|
+
raise "unable to determine entry points from entry_point (should be Hash, Array, or Executable): #{entry_point}"
|
|
48
124
|
end
|
|
49
125
|
end
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
126
|
+
|
|
127
|
+
# Returns an array of exit points, determined from exit_point.
|
|
128
|
+
def exit_points
|
|
129
|
+
case exit_point
|
|
130
|
+
when Hash then exit_point.values
|
|
131
|
+
when Support::Executable then [exit_point]
|
|
132
|
+
when Array then exit_point
|
|
133
|
+
else
|
|
134
|
+
raise "unable to determine exit points from exit_point (should be Hash, Array, or Executable): #{exit_point}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Enqueues all entry points for self and self.batch to app
|
|
139
|
+
# with the inputs. The number of inputs provided should match
|
|
140
|
+
# the number of inputs required by all the entry points;
|
|
141
|
+
# if the entry points have different input requirements, they
|
|
142
|
+
# have to be enqued separately.
|
|
143
|
+
def enq(*inputs)
|
|
144
|
+
batch.each {|t| t.unbatched_enq(*inputs) }
|
|
145
|
+
self
|
|
53
146
|
end
|
|
54
147
|
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
# Enques all entry points to app with the inputs.
|
|
149
|
+
def unbatched_enq(*inputs)
|
|
150
|
+
entry_points.each do |task|
|
|
151
|
+
app.enq(task, *inputs)
|
|
152
|
+
end
|
|
153
|
+
self
|
|
57
154
|
end
|
|
58
155
|
|
|
59
|
-
|
|
60
|
-
|
|
156
|
+
# Sets the on_complete_block for all exit points for self and
|
|
157
|
+
# self.batch. Use unbatched_on_complete to set the on_complete_block
|
|
158
|
+
# for just self.exit_points.
|
|
159
|
+
def on_complete(override=false, &block)
|
|
160
|
+
batch.each {|t| t.unbatched_on_complete(override, &block)}
|
|
161
|
+
self
|
|
61
162
|
end
|
|
62
163
|
|
|
164
|
+
# Sets the on_complete_block for all exit points for self.
|
|
165
|
+
def unbatched_on_complete(override=false, &block)
|
|
166
|
+
exit_points.each do |task|
|
|
167
|
+
task.on_complete(override, &block)
|
|
168
|
+
end
|
|
169
|
+
self
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# The workflow definition method. By default workflow
|
|
173
|
+
# simply calls the task_block. In subclasses, workflow
|
|
174
|
+
# should be overridden to provide the workflow definition.
|
|
63
175
|
def workflow
|
|
64
176
|
raise WorkflowError.new("No workflow definition provided.") unless task_block
|
|
65
177
|
task_block.call(self)
|
|
66
178
|
end
|
|
179
|
+
|
|
180
|
+
class WorkflowError < Exception # :nodoc:
|
|
181
|
+
end
|
|
67
182
|
|
|
68
|
-
|
|
69
|
-
|
|
183
|
+
# Returns the name of the workflow joined to the input. This
|
|
184
|
+
# can be convenient when naming internal tasks, as they can
|
|
185
|
+
# be grouped based on the name of the workflow. Returns
|
|
186
|
+
# the name of the workflow if input == nil.
|
|
187
|
+
def name(input=nil)
|
|
188
|
+
input == nil ? @name : File.join(@name, input)
|
|
70
189
|
end
|
|
71
190
|
|
|
72
|
-
|
|
191
|
+
# Returns name
|
|
192
|
+
def to_s
|
|
193
|
+
name
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
protected
|
|
197
|
+
|
|
198
|
+
# Hook to set a default task block. By default, nil.
|
|
199
|
+
def default_task_block
|
|
200
|
+
nil
|
|
73
201
|
end
|
|
74
202
|
end
|
|
75
203
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
key: two
|
data/test/app/config/erb.yml
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
app: <%= app.object_id %>
|
|
2
|
+
filepath: <%= filepath %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
key: one
|
data/test/app_test.rb
CHANGED
|
@@ -4,107 +4,225 @@ require 'stringio'
|
|
|
4
4
|
require 'logger'
|
|
5
5
|
|
|
6
6
|
class AppTest < Test::Unit::TestCase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
include Tap
|
|
8
|
+
include TapTestMethods
|
|
9
|
+
|
|
10
10
|
acts_as_tap_test
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
assert_equal
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
11
|
+
|
|
12
|
+
def setup
|
|
13
|
+
super
|
|
14
|
+
app.root = trs.root
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# instance tests
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
def test_instance_returns_current_instance_or_a_default_app
|
|
22
|
+
a = App.new
|
|
23
|
+
App.instance = a
|
|
24
|
+
assert_equal a, App.instance
|
|
25
|
+
|
|
26
|
+
App.instance = nil
|
|
27
|
+
assert_equal App, App.instance.class
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_instance_initializes_new_App_if_not_set
|
|
31
|
+
Tap::App.instance = nil
|
|
32
|
+
assert Tap::App.instance.kind_of?(Tap::App)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# helpers
|
|
37
|
+
#
|
|
38
|
+
|
|
39
|
+
# def stub_gemspec(name, version)
|
|
40
|
+
# spec = Gem::Specification.new
|
|
41
|
+
# spec.name = name
|
|
42
|
+
# spec.version = version
|
|
43
|
+
# spec.loaded_from = "/path/to/gems"
|
|
44
|
+
# spec
|
|
45
|
+
# end
|
|
46
|
+
|
|
47
|
+
def current_threads
|
|
48
|
+
threads = []
|
|
49
|
+
ObjectSpace.garbage_collect
|
|
50
|
+
sleep 0.2 # sleep to give garbage collect time to run
|
|
51
|
+
|
|
52
|
+
# JRuby limits ObjectSpace to only work for Class by default
|
|
53
|
+
# so this line has to be made less elegant and a little slower
|
|
54
|
+
# ObjectSpace.each_object(Thread) {|t| threads << t.object_id}
|
|
55
|
+
ObjectSpace.each_object(Class) {|t| threads << t.object_id if t.kind_of?(Thread)}
|
|
56
|
+
threads
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# check that no new threads are created during the block
|
|
60
|
+
def extended_test_with_thread_check
|
|
61
|
+
extended_test do
|
|
62
|
+
prior_threads = current_threads
|
|
63
|
+
yield
|
|
64
|
+
assert_equal prior_threads, current_threads
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_app_documentation
|
|
69
|
+
pwd = app.root
|
|
70
|
+
assert_equal(pwd, app.root)
|
|
71
|
+
assert_equal( File.expand_path(pwd +'/config'), app[:config])
|
|
72
|
+
|
|
73
|
+
some_task = Task.new 'some/task'
|
|
74
|
+
assert_equal( App.instance , some_task.app )
|
|
75
|
+
assert_equal( File.expand_path(pwd +'/config/some/task.yml') , some_task.config_file)
|
|
76
|
+
assert_equal( {:key => 'one'}, some_task.config)
|
|
77
|
+
|
|
78
|
+
another_task = Task.new 'another/task'
|
|
79
|
+
assert_equal( App.instance , another_task.app )
|
|
80
|
+
assert_equal( File.expand_path(pwd + '/config/another/task.yml') , another_task.config_file)
|
|
81
|
+
assert_equal( {:key => 'two'}, another_task.config)
|
|
82
|
+
|
|
83
|
+
###
|
|
84
|
+
t1 = Task.new {|task, input| input += 1 }
|
|
85
|
+
t1.enq 0
|
|
86
|
+
t1.enq 10
|
|
87
|
+
|
|
88
|
+
app.run
|
|
89
|
+
assert_equal [1, 11], app.results(t1)
|
|
90
|
+
|
|
91
|
+
app.aggregator.clear
|
|
92
|
+
|
|
93
|
+
t2= Task.new {|task, input| input += 10 }
|
|
94
|
+
t1.on_complete {|_result| t2.enq(_result) }
|
|
95
|
+
|
|
96
|
+
t1.enq 0
|
|
97
|
+
t1.enq 10
|
|
98
|
+
|
|
99
|
+
app.run
|
|
100
|
+
assert_equal [], app.results(t1)
|
|
101
|
+
assert_equal [11, 21], app.results(t2)
|
|
102
|
+
|
|
103
|
+
###
|
|
104
|
+
t1 = Task.new {|task, input| input += 1 }
|
|
105
|
+
t2 = Task.new {|task, input| input += 10 }
|
|
106
|
+
assert_equal [t1, t2], Task.batch(t1, t2)
|
|
107
|
+
|
|
108
|
+
t1.enq 0
|
|
109
|
+
t2.enq 10
|
|
110
|
+
|
|
111
|
+
app.run
|
|
112
|
+
assert_equal [1, 11], app.results(t1)
|
|
113
|
+
assert_equal [10, 20], app.results(t2)
|
|
114
|
+
|
|
115
|
+
lock = Mutex.new
|
|
116
|
+
array = []
|
|
117
|
+
t1 = Task.new {|task| lock.synchronize { array << Thread.current.object_id }; sleep 0.1 }
|
|
118
|
+
t2 = Task.new {|task| lock.synchronize { array << Thread.current.object_id }; sleep 0.1 }
|
|
119
|
+
|
|
120
|
+
t1.multithread = true
|
|
121
|
+
t1.enq
|
|
122
|
+
t2.multithread = true
|
|
123
|
+
t2.enq
|
|
124
|
+
|
|
125
|
+
app.run
|
|
126
|
+
assert_equal 2, array.length
|
|
127
|
+
assert_not_equal array[0], array[1]
|
|
128
|
+
|
|
129
|
+
array = []
|
|
130
|
+
Task::Base.initialize(array, :push)
|
|
131
|
+
|
|
132
|
+
array.enq(1)
|
|
133
|
+
array.enq(2)
|
|
134
|
+
|
|
135
|
+
assert array.empty?
|
|
136
|
+
app.run
|
|
137
|
+
assert_equal [1, 2], array
|
|
138
|
+
|
|
139
|
+
array = []
|
|
140
|
+
m = array._method(:push)
|
|
141
|
+
|
|
142
|
+
app.enq(m, 1)
|
|
143
|
+
app.mq(array, :push, 2)
|
|
144
|
+
|
|
145
|
+
assert array.empty?
|
|
146
|
+
app.run
|
|
147
|
+
assert_equal [1, 2], array
|
|
148
|
+
|
|
149
|
+
###
|
|
150
|
+
t1 = Tap::Task.new('add_one') {|task, input| input += 1 }
|
|
151
|
+
t2 = Tap::Task.new('add_five') {|task, input| input += 5 }
|
|
152
|
+
|
|
153
|
+
t1.on_complete do |_result|
|
|
154
|
+
_result._current < 3 ? t1.enq(_result) : t2.enq(_result)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
t1.enq(0)
|
|
158
|
+
t1.enq(1)
|
|
159
|
+
t1.enq(2)
|
|
160
|
+
|
|
161
|
+
app.run
|
|
162
|
+
assert_equal [8,8,8], app.results(t2)
|
|
163
|
+
|
|
164
|
+
strio = StringIO.new("")
|
|
165
|
+
app._results(t2).each do |_result|
|
|
166
|
+
strio.puts "How #{_result._original} became #{_result._current}:"
|
|
167
|
+
strio.puts _result._to_s
|
|
168
|
+
strio.puts
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
assert_equal(
|
|
172
|
+
%Q{How 2 became 8:
|
|
173
|
+
o-[] 2
|
|
174
|
+
o-[add_one] 3
|
|
175
|
+
o-[add_five] 8
|
|
176
|
+
|
|
177
|
+
How 1 became 8:
|
|
178
|
+
o-[] 1
|
|
179
|
+
o-[add_one] 2
|
|
180
|
+
o-[add_one] 3
|
|
181
|
+
o-[add_five] 8
|
|
182
|
+
|
|
183
|
+
How 0 became 8:
|
|
184
|
+
o-[] 0
|
|
185
|
+
o-[add_one] 1
|
|
186
|
+
o-[add_one] 2
|
|
187
|
+
o-[add_one] 3
|
|
188
|
+
o-[add_five] 8
|
|
189
|
+
|
|
190
|
+
}, strio.string)
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
#
|
|
195
|
+
# State test
|
|
196
|
+
#
|
|
197
|
+
|
|
198
|
+
def test_state_str_documentation
|
|
199
|
+
assert_equal 'READY', App::State.state_str(0)
|
|
200
|
+
assert_nil App::State.state_str(12)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# initialization tests
|
|
205
|
+
#
|
|
206
|
+
|
|
207
|
+
def test_default_app
|
|
208
|
+
app = App.new
|
|
209
|
+
|
|
210
|
+
assert_equal Dir.pwd, app.root
|
|
211
|
+
assert_equal({}, app.directories)
|
|
212
|
+
assert_equal({}, app.options.marshal_dump)
|
|
213
|
+
assert_equal({}, app.map)
|
|
214
|
+
assert_equal(Support::ExecutableQueue, app.queue.class)
|
|
215
|
+
assert app.queue.empty?
|
|
216
|
+
assert_equal(Support::Aggregator, app.aggregator.class)
|
|
217
|
+
assert app.aggregator.empty?
|
|
218
|
+
assert_equal App::State::READY, app.state
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
#
|
|
222
|
+
# task config tests
|
|
223
|
+
#
|
|
224
|
+
|
|
225
|
+
def test_config_returns_current_configurations
|
|
108
226
|
app = App.new
|
|
109
227
|
expected = {
|
|
110
228
|
:root => Dir.pwd,
|
|
@@ -155,7 +273,7 @@ class AppTest < Test::Unit::TestCase
|
|
|
155
273
|
assert_equal File.expand_path("./new/root/path/to/dir"), app[:dir]
|
|
156
274
|
assert_equal Logger::DEBUG, app.logger.level
|
|
157
275
|
end
|
|
158
|
-
|
|
276
|
+
|
|
159
277
|
def test_reconfigure_root_sets_app_root
|
|
160
278
|
app = App.new
|
|
161
279
|
|
|
@@ -219,8 +337,11 @@ class AppTest < Test::Unit::TestCase
|
|
|
219
337
|
|
|
220
338
|
class AppHandlesConfig < App
|
|
221
339
|
attr_accessor :handled_configs
|
|
340
|
+
def initialize
|
|
341
|
+
self.handled_configs = []
|
|
342
|
+
end
|
|
222
343
|
def handle_configuation(key, value)
|
|
223
|
-
|
|
344
|
+
handled_configs.concat [key, value]
|
|
224
345
|
true
|
|
225
346
|
end
|
|
226
347
|
end
|
|
@@ -237,7 +358,7 @@ class AppTest < Test::Unit::TestCase
|
|
|
237
358
|
|
|
238
359
|
class AppDoesNotHandleConfig < AppHandlesConfig
|
|
239
360
|
def handle_configuation(key, value)
|
|
240
|
-
|
|
361
|
+
handled_configs.concat [key, value]
|
|
241
362
|
false
|
|
242
363
|
end
|
|
243
364
|
end
|
|
@@ -251,27 +372,61 @@ class AppTest < Test::Unit::TestCase
|
|
|
251
372
|
assert_equal [:unknown, 'value'], app.handled_configs
|
|
252
373
|
assert was_in_block
|
|
253
374
|
end
|
|
375
|
+
|
|
376
|
+
#
|
|
377
|
+
# reload test
|
|
378
|
+
#
|
|
379
|
+
|
|
380
|
+
def test_reload_returns_unloaded_constants
|
|
381
|
+
app = Tap::App.instance
|
|
382
|
+
|
|
383
|
+
Dependencies.clear
|
|
384
|
+
assert_equal [], app.reload
|
|
385
|
+
|
|
386
|
+
begin
|
|
387
|
+
assert !Object.const_defined?("AppTestTask")
|
|
388
|
+
|
|
389
|
+
Dependencies.load_paths << app['lib']
|
|
390
|
+
app_task_test_mod = AppTestTask
|
|
391
|
+
|
|
392
|
+
assert Object.const_defined?("AppTestTask")
|
|
393
|
+
assert_equal [:AppTestTask], app.reload.collect {|c| c.to_sym }
|
|
394
|
+
assert !Object.const_defined?("AppTestTask")
|
|
395
|
+
ensure
|
|
396
|
+
Dependencies.clear
|
|
397
|
+
Dependencies.load_paths.delete(app['lib'])
|
|
398
|
+
end
|
|
399
|
+
end
|
|
254
400
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
app.logger = logger
|
|
265
|
-
assert logger.respond_to?(:section_break)
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
#
|
|
269
|
-
# TODO -- Add logging tests
|
|
270
|
-
#
|
|
401
|
+
#
|
|
402
|
+
# lookup_const test
|
|
403
|
+
#
|
|
404
|
+
|
|
405
|
+
def test_lookup_const_does_not_mishandle_top_level_constants
|
|
406
|
+
assert !Object.const_defined?('LookupModule')
|
|
407
|
+
Object.const_set('LookupModule', Module.new)
|
|
408
|
+
assert_raise(Tap::App::LookupError) { app.lookup_const('lookup_module/file') }
|
|
409
|
+
end
|
|
271
410
|
|
|
411
|
+
#
|
|
412
|
+
# set logger tests
|
|
413
|
+
#
|
|
414
|
+
|
|
415
|
+
def test_set_logger_extends_logger_with_support_logger
|
|
416
|
+
output = StringIO.new('')
|
|
417
|
+
logger = Logger.new(output)
|
|
418
|
+
assert !logger.respond_to?(:section_break)
|
|
419
|
+
|
|
420
|
+
app.logger = logger
|
|
421
|
+
assert logger.respond_to?(:section_break)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
#
|
|
425
|
+
# TODO -- Add logging tests
|
|
426
|
+
#
|
|
272
427
|
|
|
273
428
|
#
|
|
274
|
-
#
|
|
429
|
+
# task_class tests
|
|
275
430
|
#
|
|
276
431
|
|
|
277
432
|
class TaskSubClass < Task
|
|
@@ -280,11 +435,28 @@ class AppTest < Test::Unit::TestCase
|
|
|
280
435
|
class AnotherTask < Task
|
|
281
436
|
end
|
|
282
437
|
|
|
438
|
+
def test_task_class_documentation
|
|
439
|
+
t_class = app.task_class('tap/file_task')
|
|
440
|
+
assert_equal Tap::FileTask, t_class
|
|
441
|
+
|
|
442
|
+
app.map = {"mapped-task" => "Tap::FileTask"}
|
|
443
|
+
t_class = app.task_class('mapped-task-1.0')
|
|
444
|
+
assert_equal Tap::FileTask, t_class
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
#
|
|
448
|
+
# task tests
|
|
449
|
+
#
|
|
450
|
+
|
|
283
451
|
def test_task_documentation
|
|
284
|
-
|
|
452
|
+
t = app.task('tap/file_task')
|
|
453
|
+
assert_equal Tap::FileTask, t.class
|
|
454
|
+
assert_equal 'tap/file_task', t.name
|
|
455
|
+
|
|
456
|
+
app.map = {"mapped-task" => "Tap::FileTask"}
|
|
285
457
|
|
|
286
458
|
t = app.task('mapped-task-1.0', :key => 'value')
|
|
287
|
-
assert_equal
|
|
459
|
+
assert_equal Tap::FileTask, t.class
|
|
288
460
|
assert_equal "mapped-task-1.0", t.name
|
|
289
461
|
assert_equal 'value', t.config[:key]
|
|
290
462
|
end
|
|
@@ -317,9 +489,15 @@ class AppTest < Test::Unit::TestCase
|
|
|
317
489
|
|
|
318
490
|
def test_task_looks_up_task_classes_along_Dependencies_load_paths
|
|
319
491
|
begin
|
|
492
|
+
assert !Object.const_defined?("AppTestTask")
|
|
493
|
+
|
|
320
494
|
Dependencies.load_paths << app['lib']
|
|
321
|
-
|
|
495
|
+
t = app.task("AppTestTask")
|
|
496
|
+
|
|
497
|
+
assert Object.const_defined?("AppTestTask")
|
|
498
|
+
assert_equal AppTestTask, t.class
|
|
322
499
|
ensure
|
|
500
|
+
Dependencies.clear
|
|
323
501
|
Dependencies.load_paths.delete(app['lib'])
|
|
324
502
|
end
|
|
325
503
|
end
|
|
@@ -333,10 +511,15 @@ class AppTest < Test::Unit::TestCase
|
|
|
333
511
|
#
|
|
334
512
|
|
|
335
513
|
def test_task_class_name_documentation
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
assert_equal "Tap::
|
|
339
|
-
|
|
514
|
+
app.map = {"mapped-task" => "Tap::FileTask"}
|
|
515
|
+
assert_equal "some/task_class", app.task_class_name('some/task_class')
|
|
516
|
+
assert_equal "Tap::FileTask", app.task_class_name('mapped-task-1.0')
|
|
517
|
+
|
|
518
|
+
t1 = Task.new
|
|
519
|
+
assert_equal "Tap::Task", app.task_class_name(t1)
|
|
520
|
+
|
|
521
|
+
t2 = ObjectWithExecute.new.extend Tap::Task::Base
|
|
522
|
+
assert_equal "ObjectWithExecute", app.task_class_name(t2)
|
|
340
523
|
end
|
|
341
524
|
|
|
342
525
|
def test_task_class_name_returns_task_class_name
|
|
@@ -346,13 +529,13 @@ class AppTest < Test::Unit::TestCase
|
|
|
346
529
|
subtask = TaskSubClass.new
|
|
347
530
|
assert_equal "AppTest::TaskSubClass", app.task_class_name(subtask)
|
|
348
531
|
|
|
349
|
-
non_task =
|
|
532
|
+
non_task = ObjectWithExecute.new
|
|
350
533
|
non_task.extend Tap::Task::Base
|
|
351
|
-
assert_equal "
|
|
534
|
+
assert_equal "ObjectWithExecute", app.task_class_name(non_task)
|
|
352
535
|
end
|
|
353
536
|
|
|
354
|
-
def
|
|
355
|
-
assert_equal "
|
|
537
|
+
def test_task_class_name_returns_deversioned_name
|
|
538
|
+
assert_equal "app_test/task_sub_class", app.task_class_name("app_test/task_sub_class-1.1")
|
|
356
539
|
end
|
|
357
540
|
|
|
358
541
|
def test_task_class_name_resolves_names_using_map
|
|
@@ -361,145 +544,185 @@ class AppTest < Test::Unit::TestCase
|
|
|
361
544
|
end
|
|
362
545
|
|
|
363
546
|
#
|
|
364
|
-
|
|
365
|
-
|
|
547
|
+
# each_config_template tests
|
|
548
|
+
#
|
|
366
549
|
|
|
367
|
-
def
|
|
368
|
-
simple =
|
|
550
|
+
def test_each_config_template_documentation
|
|
551
|
+
simple = output_tempfile
|
|
369
552
|
File.open(simple, "w") {|f| f << "key: value"}
|
|
370
|
-
assert_equal([{"key" => "value"}], app.
|
|
553
|
+
assert_equal([{"key" => "value"}], app.each_config_template(simple))
|
|
371
554
|
|
|
372
|
-
|
|
373
|
-
File.open(
|
|
555
|
+
erb = output_tempfile
|
|
556
|
+
File.open(erb, "w") {|f| f << "app: <%= app.object_id %>\nfilepath: <%= filepath %>"}
|
|
557
|
+
assert_equal([{"app" => app.object_id, "filepath" => erb}], app.each_config_template(erb))
|
|
558
|
+
|
|
559
|
+
batched_with_erb = output_tempfile
|
|
560
|
+
File.open(batched_with_erb, "w") do |f|
|
|
374
561
|
f << %Q{
|
|
375
562
|
- key: <%= 1 %>
|
|
376
563
|
- key: <%= 1 + 1 %>}
|
|
377
564
|
end
|
|
378
|
-
assert_equal([{"key" => 1}, {"key" => 2}], app.
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
565
|
+
assert_equal([{"key" => 1}, {"key" => 2}], app.each_config_template(batched_with_erb))
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def test_each_config_template_retrieves_templates_for_versioned_config_files
|
|
569
|
+
filepath = app.filepath('config', "version.yml")
|
|
570
|
+
assert File.exists?(filepath)
|
|
571
|
+
assert_equal [{"version" => "empty"}], app.each_config_template(filepath)
|
|
572
|
+
|
|
573
|
+
filepath = app.filepath('config', "version-0.1.yml")
|
|
574
|
+
assert File.exists?(filepath)
|
|
575
|
+
assert_equal [{"version" => 0.1}], app.each_config_template(filepath)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
def test_each_config_template_can_load_an_array_of_templates
|
|
579
|
+
filepath = app.filepath('config', "batch.yml")
|
|
580
|
+
assert File.exists?(filepath)
|
|
581
|
+
assert_equal [{"key" => "one"}, {"key" => "two"}], app.each_config_template(filepath)
|
|
582
|
+
end
|
|
396
583
|
|
|
397
|
-
|
|
584
|
+
def test_each_config_template_returns_empty_template_even_if_config_file_does_not_exist
|
|
398
585
|
filepath = app.filepath('config', "non_existant.yml")
|
|
399
586
|
assert !File.exists?(filepath)
|
|
400
|
-
|
|
587
|
+
assert_equal [{}], app.each_config_template(filepath)
|
|
401
588
|
end
|
|
402
589
|
|
|
403
|
-
def
|
|
590
|
+
def test_each_config_template_returns_empty_template_if_config_file_is_empty
|
|
404
591
|
filepath = app.filepath('config', "empty.yml")
|
|
405
592
|
assert File.exists?(filepath)
|
|
406
593
|
assert_equal "", File.read(filepath)
|
|
407
|
-
|
|
594
|
+
assert_equal [{}], app.each_config_template(filepath)
|
|
408
595
|
end
|
|
409
596
|
|
|
410
|
-
def
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
597
|
+
def test_each_config_template_templates_using_erb
|
|
598
|
+
filepath = app.filepath('config', "erb.yml")
|
|
599
|
+
assert_equal [{"filepath" => filepath, "app" => app.object_id}], app.each_config_template(filepath)
|
|
600
|
+
end
|
|
414
601
|
|
|
415
602
|
#
|
|
416
|
-
#
|
|
603
|
+
# config_filepath test
|
|
417
604
|
#
|
|
418
605
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
#
|
|
425
|
-
#
|
|
426
|
-
#
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
606
|
+
def test_config_filepath
|
|
607
|
+
assert_equal nil, app.config_filepath(nil)
|
|
608
|
+
assert_equal File.join(app['config'], "task/name.yml"), app.config_filepath("task/name")
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
#
|
|
612
|
+
# ready test
|
|
613
|
+
#
|
|
614
|
+
|
|
615
|
+
def test_ready_sets_state_to_READY_unless_running
|
|
616
|
+
app.instance_variable_set('@state', App::State::STOP)
|
|
617
|
+
assert_not_equal App::State::READY, app.state
|
|
618
|
+
|
|
619
|
+
assert_equal app, app.ready
|
|
620
|
+
assert_equal App::State::READY, app.state
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def test_ready_does_not_sets_state_to_READY_when_running
|
|
624
|
+
was_in_block = false
|
|
625
|
+
|
|
626
|
+
t = Tap::Task.new do |task|
|
|
627
|
+
assert_equal App::State::RUN, app.state
|
|
628
|
+
task.app.ready
|
|
629
|
+
assert_equal App::State::RUN, app.state
|
|
630
|
+
|
|
631
|
+
task.app.stop
|
|
632
|
+
assert_equal App::State::STOP, app.state
|
|
633
|
+
task.app.ready
|
|
634
|
+
assert_equal App::State::STOP, app.state
|
|
635
|
+
|
|
636
|
+
was_in_block = true
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
with_options :debug => true do
|
|
640
|
+
t.enq
|
|
641
|
+
app.run
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
assert was_in_block
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
#
|
|
648
|
+
# run tests
|
|
649
|
+
#
|
|
650
|
+
|
|
651
|
+
def test_run_single_task
|
|
652
|
+
t = Task.new(&add_one)
|
|
653
|
+
with_options :debug => true do
|
|
654
|
+
t.enq 1
|
|
655
|
+
app.run
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
assert_audit_equal(ExpAudit[[nil, 1], [t,2]], app._results(t).first)
|
|
659
|
+
assert_equal [1], runlist
|
|
660
|
+
end
|
|
432
661
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
662
|
+
def test_run_single_task_from_a_thread
|
|
663
|
+
t = Task.new(&add_one)
|
|
664
|
+
with_options :debug => true do
|
|
665
|
+
t.enq 1
|
|
666
|
+
th = Thread.new { app.run }
|
|
667
|
+
th.join
|
|
668
|
+
end
|
|
436
669
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
0 => [[nil,1], [t,2]],
|
|
445
|
-
1 => [[nil,2], [t,3]],
|
|
446
|
-
2 => [[nil,3], [t,4]])
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
def test_run_single_task_from_a_thread
|
|
450
|
-
t = Task.new(&add_one)
|
|
451
|
-
|
|
452
|
-
th = Thread.new { app.run(t,1,2,3) }
|
|
453
|
-
th.join
|
|
454
|
-
|
|
455
|
-
assert_inputs(t => [1,2,3])
|
|
456
|
-
assert_outputs(t => [2,3,4])
|
|
457
|
-
assert_equal [1,2,3], runlist
|
|
458
|
-
assert_audits(t.results,
|
|
459
|
-
0 => [[nil,1], [t,2]],
|
|
460
|
-
1 => [[nil,2], [t,3]],
|
|
461
|
-
2 => [[nil,3], [t,4]])
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
#
|
|
465
|
-
# multithread test
|
|
466
|
-
#
|
|
670
|
+
assert_audit_equal(ExpAudit[[nil, 1], [t,2]], app._results(t).first)
|
|
671
|
+
assert_equal [1], runlist
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
#
|
|
675
|
+
# multithread test
|
|
676
|
+
#
|
|
467
677
|
|
|
468
678
|
def test_main_thread_execution_waits_for_multithread_execution
|
|
469
679
|
extended_test do
|
|
470
680
|
main_thread_ran = false
|
|
681
|
+
check_thread_ran = false
|
|
471
682
|
multithread_ran = false
|
|
472
683
|
|
|
473
684
|
multithread_executing = false
|
|
474
685
|
main_thread_did_not_wait = false
|
|
686
|
+
multithread_did_not_wait = false
|
|
475
687
|
|
|
476
|
-
|
|
688
|
+
t1 = Task.new do |task|
|
|
477
689
|
main_thread_ran = true
|
|
478
690
|
main_thread_did_not_wait = true if multithread_executing
|
|
479
691
|
end
|
|
480
692
|
|
|
481
|
-
|
|
693
|
+
t2 = Task.new do |task|
|
|
694
|
+
check_thread_ran = true
|
|
695
|
+
multithread_did_not_wait = true if multithread_executing
|
|
696
|
+
end
|
|
697
|
+
t2.multithread = true
|
|
698
|
+
|
|
699
|
+
t3 = Task.new do |task|
|
|
482
700
|
multithread_ran = true
|
|
483
701
|
multithread_executing = true
|
|
484
702
|
|
|
485
703
|
# sleep is necessary so the other threads
|
|
486
704
|
# have an opportunity to execute
|
|
487
|
-
sleep(0.
|
|
705
|
+
sleep(0.1)
|
|
488
706
|
|
|
489
707
|
multithread_executing = false
|
|
490
708
|
end
|
|
491
|
-
|
|
709
|
+
t3.multithread = true
|
|
492
710
|
|
|
493
|
-
|
|
494
|
-
|
|
711
|
+
t3.enq
|
|
712
|
+
t2.enq
|
|
713
|
+
t1.enq
|
|
495
714
|
|
|
496
|
-
|
|
715
|
+
with_options :debug => true do
|
|
716
|
+
app.run
|
|
717
|
+
end
|
|
497
718
|
|
|
498
719
|
assert main_thread_ran
|
|
499
720
|
assert multithread_ran
|
|
721
|
+
assert check_thread_ran
|
|
500
722
|
assert !main_thread_did_not_wait
|
|
723
|
+
assert multithread_did_not_wait
|
|
501
724
|
end
|
|
502
|
-
|
|
725
|
+
end
|
|
503
726
|
|
|
504
727
|
def test_multithread_execution_waits_for_main_thread_execution
|
|
505
728
|
extended_test do
|
|
@@ -509,430 +732,326 @@ class AppTest < Test::Unit::TestCase
|
|
|
509
732
|
multithread_did_not_wait = false
|
|
510
733
|
main_thread_executing = false
|
|
511
734
|
|
|
512
|
-
|
|
735
|
+
t1 = Task.new do |task|
|
|
513
736
|
multithread_ran = true
|
|
514
737
|
multithread_did_not_wait = true if main_thread_executing
|
|
515
738
|
end
|
|
516
739
|
t1.multithread = true
|
|
517
|
-
|
|
518
|
-
|
|
740
|
+
|
|
741
|
+
t2 = Task.new do |task|
|
|
519
742
|
main_thread_ran = true
|
|
520
743
|
main_thread_executing = true
|
|
521
744
|
|
|
522
745
|
# sleep is necessary so the other threads
|
|
523
746
|
# have an opportunity to execute
|
|
524
|
-
sleep(0.
|
|
747
|
+
sleep(0.1)
|
|
525
748
|
|
|
526
749
|
main_thread_executing = false
|
|
527
750
|
end
|
|
528
751
|
|
|
529
|
-
|
|
530
|
-
|
|
752
|
+
t2.enq
|
|
753
|
+
t1.enq
|
|
531
754
|
|
|
532
|
-
|
|
755
|
+
with_options :debug => true do
|
|
756
|
+
app.run
|
|
757
|
+
end
|
|
533
758
|
|
|
534
759
|
assert main_thread_ran
|
|
535
760
|
assert multithread_ran
|
|
536
761
|
assert !multithread_did_not_wait
|
|
537
762
|
end
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
# the logic of this test is that IF app executes
|
|
546
|
-
# in a multithreaded manner, then max_threads will
|
|
547
|
-
# be greater than 1. Furthermore, IF the :max_threads
|
|
548
|
-
# option is respected, then max_threads shouldn't be
|
|
549
|
-
# greater than 2.
|
|
550
|
-
block = lambda do
|
|
551
|
-
n_threads += 1
|
|
552
|
-
max_threads = n_threads if n_threads > max_threads
|
|
553
|
-
|
|
554
|
-
# sleep is necessary so the other threads
|
|
555
|
-
# have an opportunity to execute
|
|
556
|
-
sleep(0.2)
|
|
557
|
-
|
|
558
|
-
n_threads -= 1
|
|
559
|
-
nil
|
|
560
|
-
end
|
|
561
|
-
|
|
562
|
-
t1 = Task.new(&block)
|
|
563
|
-
t2 = Task.new(&block)
|
|
564
|
-
t3 = Task.new(&block)
|
|
565
|
-
|
|
566
|
-
with_options(:max_threads => 2) do
|
|
567
|
-
t1.enq nil
|
|
568
|
-
t2.enq nil
|
|
569
|
-
t3.enq nil
|
|
570
|
-
app.multithread(t1,t2,t3)
|
|
571
|
-
|
|
572
|
-
app.run
|
|
573
|
-
|
|
574
|
-
assert_equal 2, max_threads
|
|
575
|
-
end
|
|
576
|
-
end
|
|
577
|
-
end
|
|
578
|
-
|
|
579
|
-
def test_a_multithreaded_task_executes_only_on_one_thread_at_a_time
|
|
580
|
-
extended_test do
|
|
581
|
-
max_threads = 0
|
|
582
|
-
n_threads = 0
|
|
583
|
-
count = 0
|
|
584
|
-
threads = []
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
def test_only_max_threads_will_be_executed_at_a_time
|
|
766
|
+
extended_test do
|
|
767
|
+
max_threads = 0
|
|
768
|
+
n_threads = 0
|
|
585
769
|
|
|
586
|
-
|
|
587
|
-
#
|
|
588
|
-
#
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
count += 1
|
|
595
|
-
task.enq nil if count < 3
|
|
770
|
+
# the logic of this test is that if app executes
|
|
771
|
+
# in a multithreaded manner, then max_threads will
|
|
772
|
+
# be greater than 1. Furthermore, if the max_threads
|
|
773
|
+
# option is respected, then max_threads shouldn't be
|
|
774
|
+
# greater than 2.
|
|
775
|
+
block = lambda do |task|
|
|
776
|
+
n_threads += 1
|
|
777
|
+
max_threads = n_threads if n_threads > max_threads
|
|
596
778
|
|
|
597
779
|
# sleep is necessary so the other threads
|
|
598
780
|
# have an opportunity to execute
|
|
599
|
-
|
|
781
|
+
sleep(0.1)
|
|
600
782
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
783
|
+
n_threads -= 1
|
|
784
|
+
nil
|
|
785
|
+
end
|
|
604
786
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
runlist = []
|
|
622
|
-
|
|
623
|
-
# if the :max_threads option is respected, then max_threads
|
|
624
|
-
# shouldn't be greater than 2. if multithread execution
|
|
625
|
-
# happened, then max_threads will be greater than 1.
|
|
626
|
-
block = lambda do |task, input|
|
|
627
|
-
runlist << input
|
|
628
|
-
|
|
629
|
-
n_threads += 1
|
|
630
|
-
max_threads = n_threads if n_threads > max_threads
|
|
631
|
-
|
|
632
|
-
# sleep is necessary so the other threads
|
|
633
|
-
# have an opportunity to execute
|
|
634
|
-
sleep(0.2)
|
|
635
|
-
|
|
636
|
-
n_threads -= 1
|
|
637
|
-
nil
|
|
638
|
-
end
|
|
639
|
-
|
|
640
|
-
t1 = Task.new(&block)
|
|
641
|
-
t2 = Task.new(&block)
|
|
642
|
-
t3 = Task.new(&block)
|
|
643
|
-
|
|
644
|
-
with_options(:max_threads => 2) do
|
|
645
|
-
t1.enq 1, 2
|
|
646
|
-
t2.enq 3
|
|
647
|
-
t3.enq 4
|
|
648
|
-
app.multithread(t1,t2,t3)
|
|
649
|
-
|
|
650
|
-
app.run
|
|
651
|
-
|
|
652
|
-
assert_equal 2, max_threads
|
|
653
|
-
# t1 passes [1,2] as inputs
|
|
654
|
-
# t1(1) executes, then pauses, leading to
|
|
655
|
-
# t2(3) executing. Next t1 unpauses to execute
|
|
656
|
-
# t1(2) because no more threads are available. Lastly
|
|
657
|
-
# t3(4) executes
|
|
658
|
-
assert_equal [1,3,2,4], runlist
|
|
659
|
-
end
|
|
660
|
-
end
|
|
661
|
-
end
|
|
662
|
-
|
|
663
|
-
def current_threads
|
|
664
|
-
threads = []
|
|
665
|
-
ObjectSpace.garbage_collect
|
|
666
|
-
sleep 0.2 # sleep to give garbage collect time to run
|
|
667
|
-
|
|
668
|
-
# JRuby limits ObjectSpace to only work for Class by default
|
|
669
|
-
# so this line has to be made less elegant and a little slower
|
|
670
|
-
# ObjectSpace.each_object(Thread) {|t| threads << t.object_id}
|
|
671
|
-
ObjectSpace.each_object(Class) {|t| threads << t.object_id if t.kind_of?(Thread)}
|
|
672
|
-
threads
|
|
673
|
-
end
|
|
674
|
-
|
|
675
|
-
def extended_test_with_thread_check
|
|
676
|
-
extended_test do
|
|
677
|
-
prior_threads = current_threads
|
|
678
|
-
yield
|
|
679
|
-
assert_equal prior_threads, current_threads
|
|
787
|
+
t1 = Task.new(&block)
|
|
788
|
+
t2 = Task.new(&block)
|
|
789
|
+
t3 = Task.new(&block)
|
|
790
|
+
|
|
791
|
+
with_options(:max_threads => 2) do
|
|
792
|
+
[t1,t2,t3].each do |t|
|
|
793
|
+
t.enq
|
|
794
|
+
t.multithread = true
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
with_options :debug => true do
|
|
798
|
+
app.run
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
assert_equal 2, max_threads
|
|
802
|
+
end
|
|
680
803
|
end
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
Task.new do |task
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
def test_no_new_threads_appear_after_clean_multithread_exit
|
|
807
|
+
extended_test_with_thread_check do
|
|
808
|
+
max_threads = 0
|
|
809
|
+
n_threads = 0
|
|
810
|
+
|
|
811
|
+
tasks = Array.new(3) do
|
|
812
|
+
Task.new do |task|
|
|
813
|
+
n_threads += 1
|
|
814
|
+
max_threads = n_threads if n_threads > max_threads
|
|
815
|
+
sleep 0.1
|
|
816
|
+
n_threads -= 1
|
|
694
817
|
end
|
|
695
818
|
end
|
|
696
819
|
tasks.each do |task|
|
|
697
820
|
task.multithread = true
|
|
698
|
-
task.enq
|
|
821
|
+
task.enq
|
|
699
822
|
end
|
|
700
823
|
|
|
701
824
|
app.run
|
|
702
825
|
|
|
703
826
|
assert_equal 3, max_threads
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
827
|
+
end
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
# JRuby inconsistent test?
|
|
831
|
+
# 2 max_threads expected but was 1
|
|
832
|
+
def test_no_new_threads_appear_after_clean_main_thread_exit
|
|
833
|
+
extended_test_with_thread_check do
|
|
834
|
+
max_threads = 0
|
|
835
|
+
n_threads = 0
|
|
836
|
+
|
|
837
|
+
tasks = Array.new(3) do
|
|
838
|
+
Task.new do |task|
|
|
839
|
+
n_threads += 1
|
|
840
|
+
max_threads = n_threads if n_threads > max_threads
|
|
841
|
+
sleep 0.1
|
|
842
|
+
n_threads -= 1
|
|
718
843
|
end
|
|
719
844
|
end
|
|
720
845
|
non_threaded = tasks.shift
|
|
721
846
|
tasks.each do |task|
|
|
722
847
|
task.multithread = true
|
|
723
|
-
task.enq
|
|
848
|
+
task.enq
|
|
724
849
|
end
|
|
725
|
-
non_threaded.enq
|
|
850
|
+
non_threaded.enq
|
|
726
851
|
|
|
727
852
|
app.run
|
|
728
853
|
|
|
729
854
|
assert_equal 2, max_threads
|
|
730
|
-
|
|
731
|
-
|
|
855
|
+
end
|
|
856
|
+
end
|
|
732
857
|
|
|
733
|
-
|
|
734
858
|
#
|
|
735
859
|
# stop test
|
|
736
860
|
#
|
|
737
861
|
|
|
738
862
|
def test_stop_prevents_non_executing_tasks_from_executing_on_main_thread
|
|
739
|
-
|
|
863
|
+
extended_test_with_thread_check do
|
|
740
864
|
count = 0
|
|
741
865
|
tasks = Array.new(5) do
|
|
742
|
-
Task.new do |task
|
|
866
|
+
Task.new do |task|
|
|
743
867
|
count += 1
|
|
744
868
|
app.stop if count == 2
|
|
745
869
|
end
|
|
746
870
|
end
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
871
|
+
tasks.each do |task|
|
|
872
|
+
task.enq
|
|
873
|
+
end
|
|
750
874
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
875
|
+
# under these conditions, 2 tasks should be
|
|
876
|
+
# executed on 2 threads, and 2 additional tasks
|
|
877
|
+
# dequeued into the thread queue. on stop, the 2
|
|
878
|
+
# executing tasks should finish normally, and NO MORE
|
|
879
|
+
# tasks executed. The waiting tasks will be requeued.
|
|
880
|
+
with_options :max_threads => 2, :debug => true do
|
|
881
|
+
app.run
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
assert_equal 2, count
|
|
885
|
+
assert_equal 3, app.queue.size
|
|
886
|
+
|
|
887
|
+
queued_tasks = []
|
|
888
|
+
while !app.queue.empty?
|
|
889
|
+
task, inputs = app.queue.deq
|
|
890
|
+
queued_tasks << task
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
# check that the requeued tasks are in order
|
|
894
|
+
assert_equal tasks[2...5], queued_tasks
|
|
895
|
+
end
|
|
772
896
|
end
|
|
773
897
|
|
|
774
898
|
def test_stop_prevents_non_executing_tasks_from_executing_on_threads_and_requeues_thread_queue
|
|
775
|
-
|
|
899
|
+
extended_test_with_thread_check do
|
|
776
900
|
count = 0
|
|
777
901
|
tasks = Array.new(5) do
|
|
778
|
-
Task.new do |task
|
|
902
|
+
Task.new do |task|
|
|
779
903
|
count += 1
|
|
780
|
-
sleep 0.
|
|
904
|
+
sleep 0.1
|
|
781
905
|
app.stop if count == 2
|
|
782
|
-
sleep 0.
|
|
906
|
+
sleep 0.1
|
|
783
907
|
end
|
|
784
908
|
end
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
909
|
+
tasks.each do |task|
|
|
910
|
+
task.multithread = true
|
|
911
|
+
task.enq
|
|
912
|
+
end
|
|
789
913
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
914
|
+
# under these conditions, 2 tasks should be
|
|
915
|
+
# executed on 2 threads, and 2 additional tasks
|
|
916
|
+
# dequeued into the thread queue. on stop, the 2
|
|
917
|
+
# executing tasks should finish normally, and NO MORE
|
|
918
|
+
# tasks executed. The waiting tasks will be requeued.
|
|
919
|
+
with_options :max_threads => 2, :debug => true do
|
|
920
|
+
app.run
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
assert_equal 2, count
|
|
924
|
+
assert_equal 3, app.queue.size
|
|
925
|
+
|
|
926
|
+
queued_tasks = []
|
|
927
|
+
while !app.queue.empty?
|
|
928
|
+
task, inputs = app.queue.deq
|
|
929
|
+
queued_tasks << task
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
# check that the requeued tasks are in order
|
|
933
|
+
assert_equal tasks[2...5], queued_tasks
|
|
934
|
+
end
|
|
811
935
|
end
|
|
812
936
|
|
|
813
937
|
#
|
|
814
938
|
# terminate test
|
|
815
939
|
#
|
|
816
940
|
|
|
817
|
-
# TODO -- REWORD
|
|
818
941
|
def test_terminate_from_main_thread_raises_run_error
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
task = Task.new do |
|
|
942
|
+
extended_test_with_thread_check do
|
|
943
|
+
was_terminated = true
|
|
944
|
+
task = Task.new do |t|
|
|
822
945
|
app.terminate
|
|
823
|
-
|
|
824
|
-
|
|
946
|
+
t.check_terminate
|
|
947
|
+
was_terminated = false
|
|
825
948
|
end
|
|
826
949
|
|
|
827
|
-
task.enq
|
|
950
|
+
task.enq
|
|
828
951
|
with_options :debug => true do
|
|
829
952
|
begin
|
|
830
953
|
app.run
|
|
831
954
|
flunk "no error was raised"
|
|
832
955
|
rescue
|
|
833
956
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
834
|
-
assert $!.
|
|
835
|
-
assert $!.terminate_errors.empty?
|
|
957
|
+
assert $!.errors.empty?
|
|
836
958
|
end
|
|
837
959
|
end
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
960
|
+
|
|
961
|
+
assert was_terminated
|
|
962
|
+
end
|
|
841
963
|
end
|
|
842
964
|
|
|
843
|
-
# TODO -- REWORD
|
|
844
965
|
def test_terminate_from_main_thread_when_error_is_handled_still_raises_error
|
|
845
|
-
|
|
966
|
+
extended_test_with_thread_check do
|
|
846
967
|
terminate_error_handled = false
|
|
847
|
-
task = Task.new do |
|
|
968
|
+
task = Task.new do |t|
|
|
848
969
|
begin
|
|
849
970
|
app.terminate
|
|
850
|
-
|
|
971
|
+
t.check_terminate
|
|
851
972
|
rescue
|
|
852
973
|
terminate_error_handled = true
|
|
853
974
|
end
|
|
854
975
|
end
|
|
855
976
|
|
|
856
|
-
task.enq
|
|
977
|
+
task.enq
|
|
857
978
|
with_options :debug => true do
|
|
858
979
|
begin
|
|
859
980
|
app.run
|
|
860
981
|
flunk "no error was raised"
|
|
861
982
|
rescue
|
|
862
983
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
863
|
-
assert $!.
|
|
864
|
-
assert $!.terminate_errors.empty?
|
|
984
|
+
assert $!.errors.empty?
|
|
865
985
|
end
|
|
866
986
|
end
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
987
|
+
|
|
988
|
+
assert terminate_error_handled
|
|
989
|
+
end
|
|
870
990
|
end
|
|
871
991
|
|
|
872
|
-
# TODO -- REWORD
|
|
873
992
|
def test_terminate_raises_error_on_each_execution_thread_and_requeues_thread_queue
|
|
874
|
-
|
|
993
|
+
extended_test_with_thread_check do
|
|
875
994
|
count = 0
|
|
876
995
|
some_thread_was_not_terminated = false
|
|
877
996
|
tasks = Array.new(5) do
|
|
878
|
-
Task.new do |task
|
|
997
|
+
Task.new do |task|
|
|
879
998
|
count += 1
|
|
880
999
|
app.terminate if count == 2
|
|
881
|
-
sleep
|
|
1000
|
+
sleep 0.8
|
|
882
1001
|
task.check_terminate
|
|
883
1002
|
some_thread_was_not_terminated = true
|
|
884
1003
|
end
|
|
885
1004
|
end
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1005
|
+
tasks.each do |task|
|
|
1006
|
+
task.multithread = true
|
|
1007
|
+
task.enq
|
|
1008
|
+
end
|
|
890
1009
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1010
|
+
# under these conditions, 2 tasks should be
|
|
1011
|
+
# executed on 2 threads, and 2 additional tasks
|
|
1012
|
+
# dequeued into the thread queue. on stop, the 2
|
|
1013
|
+
# executing tasks should be terminated, and NO MORE
|
|
1014
|
+
# tasks executed. The waiting tasks will be requeued.
|
|
1015
|
+
with_options :max_threads => 2, :debug => true do
|
|
897
1016
|
begin
|
|
898
1017
|
app.run
|
|
899
1018
|
flunk "no error was raised"
|
|
900
1019
|
rescue
|
|
901
1020
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
902
|
-
assert $!.
|
|
903
|
-
assert $!.terminate_errors.empty?
|
|
1021
|
+
assert $!.errors.empty?
|
|
904
1022
|
end
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
assert_equal 2, count
|
|
1026
|
+
assert_equal 3, app.queue.size
|
|
1027
|
+
assert !some_thread_was_not_terminated
|
|
910
1028
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
1029
|
+
queued_tasks = []
|
|
1030
|
+
while !app.queue.empty?
|
|
1031
|
+
task, inputs = app.queue.deq
|
|
1032
|
+
queued_tasks << task
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
# check that the requeued tasks are in order
|
|
1036
|
+
assert_equal tasks[2...5], queued_tasks
|
|
1037
|
+
end
|
|
920
1038
|
end
|
|
921
1039
|
|
|
922
|
-
# TODO -- REWORD
|
|
923
1040
|
# JRuby inconsistent test
|
|
1041
|
+
# RESOLVED? 2008/01/29
|
|
1042
|
+
# -- still can be an issue, if the sleep time is too short --
|
|
924
1043
|
def test_terminate_on_thread_when_error_is_handled_still_raises_error
|
|
925
|
-
|
|
1044
|
+
extended_test_with_thread_check do
|
|
926
1045
|
count = 0
|
|
927
1046
|
some_thread_was_not_terminated = false
|
|
928
1047
|
handled_count = 0
|
|
929
1048
|
|
|
930
1049
|
tasks = Array.new(5) do
|
|
931
|
-
Task.new do |task
|
|
1050
|
+
Task.new do |task|
|
|
932
1051
|
count += 1
|
|
933
1052
|
begin
|
|
934
1053
|
app.terminate if count == 2
|
|
935
|
-
sleep
|
|
1054
|
+
sleep 0.8
|
|
936
1055
|
task.check_terminate
|
|
937
1056
|
some_thread_was_not_terminated = true
|
|
938
1057
|
rescue
|
|
@@ -940,31 +1059,30 @@ class AppTest < Test::Unit::TestCase
|
|
|
940
1059
|
end
|
|
941
1060
|
end
|
|
942
1061
|
end
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1062
|
+
tasks.each do |task|
|
|
1063
|
+
task.multithread = true
|
|
1064
|
+
task.enq
|
|
1065
|
+
end
|
|
947
1066
|
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1067
|
+
# under these conditions, 2 tasks should be
|
|
1068
|
+
# executed on 2 threads, and 2 additional tasks
|
|
1069
|
+
# dequeued into the thread queue. on stop, the 2
|
|
1070
|
+
# executing tasks should be terminated, and NO MORE
|
|
1071
|
+
# tasks executed. The waiting tasks will be requeued.
|
|
1072
|
+
with_options :max_threads => 2, :debug => true do
|
|
954
1073
|
begin
|
|
955
1074
|
app.run
|
|
956
1075
|
flunk "no error was raised"
|
|
957
1076
|
rescue
|
|
958
1077
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
959
|
-
assert $!.
|
|
960
|
-
assert $!.terminate_errors.empty?
|
|
1078
|
+
assert $!.errors.empty?
|
|
961
1079
|
end
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
assert !some_thread_was_not_terminated
|
|
1083
|
+
assert_equal 2, count
|
|
1084
|
+
assert_equal 2, handled_count
|
|
1085
|
+
assert_equal 3, app.queue.size
|
|
968
1086
|
end
|
|
969
1087
|
end
|
|
970
1088
|
|
|
@@ -973,477 +1091,567 @@ class AppTest < Test::Unit::TestCase
|
|
|
973
1091
|
#
|
|
974
1092
|
|
|
975
1093
|
def test_info_provides_information_string
|
|
976
|
-
assert_equal 'state: 0 (READY) queue: 0
|
|
1094
|
+
assert_equal 'state: 0 (READY) queue: 0 thread_queue: 0 threads: 0 results: 0', app.info
|
|
977
1095
|
end
|
|
978
1096
|
|
|
979
1097
|
# TODO -- JRuby inconsistent test
|
|
1098
|
+
# RESOLVED? 2007/01/30
|
|
980
1099
|
def test_info_can_be_called_during_a_run
|
|
981
1100
|
extended_test do
|
|
1101
|
+
lock = Monitor.new
|
|
982
1102
|
count = 0
|
|
983
1103
|
info_str = nil
|
|
984
1104
|
|
|
985
1105
|
tasks = Array.new(5) do
|
|
986
|
-
Task.new do |task
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1106
|
+
Task.new do |task|
|
|
1107
|
+
|
|
1108
|
+
lock.synchronize do
|
|
1109
|
+
count += 1
|
|
1110
|
+
if count == 2
|
|
1111
|
+
info_str = app.info
|
|
1112
|
+
app.stop
|
|
1113
|
+
end
|
|
991
1114
|
end
|
|
992
|
-
|
|
1115
|
+
|
|
1116
|
+
sleep 0.8
|
|
993
1117
|
end
|
|
994
1118
|
end
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1119
|
+
tasks.each do |task|
|
|
1120
|
+
task.enq
|
|
1121
|
+
task.multithread = true
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
with_options :max_threads => 2 do
|
|
1001
1125
|
app.run
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
# There is some ambiguity in the info string --
|
|
1005
|
-
# waiting in the queue or in the thread queue
|
|
1006
|
-
#
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1126
|
+
end
|
|
1127
|
+
|
|
1128
|
+
# There is some ambiguity in the info string -- tasks
|
|
1129
|
+
# could be waiting in the queue or in the thread queue
|
|
1130
|
+
# and additionally, the thread queue may have nils to
|
|
1131
|
+
# signal the threads to terminate
|
|
1132
|
+
assert info_str =~ /state: 1 \(RUN\) queue: \d thread_queue: \d threads: 2 results: \d/, info_str
|
|
1133
|
+
assert_equal 'state: 0 (READY) queue: 3 thread_queue: 0 threads: 0 results: 2', app.info
|
|
1134
|
+
end
|
|
1135
|
+
end
|
|
1136
|
+
|
|
1137
|
+
#
|
|
1138
|
+
# enq test
|
|
1139
|
+
#
|
|
1140
|
+
|
|
1141
|
+
def test_enq
|
|
1142
|
+
t = Task.new
|
|
1143
|
+
assert app.queue.empty?
|
|
1144
|
+
app.enq(t)
|
|
1145
|
+
assert_equal [[t, []]], app.queue.to_a
|
|
1146
|
+
end
|
|
1147
|
+
|
|
1148
|
+
def test_enq_enques_each_task_in_task_batch
|
|
1149
|
+
t1 = Task.new
|
|
1150
|
+
t2 = t1.initialize_batch_obj
|
|
1151
|
+
|
|
1152
|
+
assert app.queue.empty?
|
|
1153
|
+
app.enq(t1)
|
|
1154
|
+
assert_equal [[t1, []], [t2, []]], app.queue.to_a
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
def test_enq_allows_methods
|
|
1158
|
+
m = []._method(:push)
|
|
1159
|
+
assert app.queue.empty?
|
|
1160
|
+
app.enq(m)
|
|
1161
|
+
assert_equal [[m, []]], app.queue.to_a
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
def test_enq_returns_enqued_task
|
|
1165
|
+
t = Task.new
|
|
1166
|
+
assert_equal t, app.enq(t)
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
#
|
|
1170
|
+
# mq test
|
|
1171
|
+
#
|
|
1172
|
+
|
|
1173
|
+
def test_mq
|
|
1174
|
+
a = []
|
|
1175
|
+
assert app.queue.empty?
|
|
1176
|
+
m = app.mq(a, :push, 1, 2)
|
|
1177
|
+
assert_equal [[m, [1,2]]], app.queue.to_a
|
|
1011
1178
|
end
|
|
1012
1179
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
#
|
|
1050
|
-
# fork tests
|
|
1051
|
-
#
|
|
1052
|
-
|
|
1053
|
-
def test_run_fork
|
|
1054
|
-
t1 = Task.new(&add_one)
|
|
1055
|
-
t2 = Task.new(&add_one)
|
|
1056
|
-
t3 = Task.new(&add_one)
|
|
1057
|
-
|
|
1058
|
-
app.fork(t1, t2, t3)
|
|
1059
|
-
app.run(t1,1,2,3)
|
|
1060
|
-
|
|
1061
|
-
assert_inputs(t1 => [1,2,3], t2 => [2,3,4], t3 => [2,3,4])
|
|
1062
|
-
assert_outputs(t1 => [2,3,4], t2 => [3,4,5], t3 => [3,4,5])
|
|
1063
|
-
assert_equal [1,2,3, 2,3,4, 2,3,4], runlist
|
|
1064
|
-
assert_audits(t2.results,
|
|
1065
|
-
0 => [[nil,1], [t1,2], [t2,3]],
|
|
1066
|
-
1 => [[nil,2], [t1,3], [t2,4]],
|
|
1067
|
-
2 => [[nil,3], [t1,4], [t2,5]])
|
|
1068
|
-
assert_audits(t3.results,
|
|
1069
|
-
0 => [[nil,1], [t1,2], [t3,3]],
|
|
1070
|
-
1 => [[nil,2], [t1,3], [t3,4]],
|
|
1071
|
-
2 => [[nil,3], [t1,4], [t3,5]])
|
|
1072
|
-
end
|
|
1073
|
-
|
|
1074
|
-
#
|
|
1075
|
-
# merge tests
|
|
1076
|
-
#
|
|
1077
|
-
|
|
1078
|
-
def test_run_merge
|
|
1079
|
-
t1 = Task.new(&add_one)
|
|
1080
|
-
t2 = Task.new(&add_one)
|
|
1081
|
-
t3 = Task.new(&add_one)
|
|
1082
|
-
|
|
1083
|
-
# merge by default has no conditions on execution
|
|
1084
|
-
# so t3 should execute immediately after t1/t2 finishes
|
|
1085
|
-
# as such the results need to be collected separately
|
|
1086
|
-
t3_results = []
|
|
1087
|
-
t3.on_complete do |results|
|
|
1088
|
-
t3_results.concat results
|
|
1180
|
+
# #
|
|
1181
|
+
# # on_complete tests
|
|
1182
|
+
# #
|
|
1183
|
+
#
|
|
1184
|
+
# def test_on_complete
|
|
1185
|
+
# t1 = Task.new(&add_one)
|
|
1186
|
+
# t2 = Task.new(&add_one)
|
|
1187
|
+
# t3 = Task.new(&add_one)
|
|
1188
|
+
#
|
|
1189
|
+
# app.on_complete(t1) do |result|
|
|
1190
|
+
# t2.enq result
|
|
1191
|
+
# t3.enq result
|
|
1192
|
+
# end
|
|
1193
|
+
# with_options :debug => true do
|
|
1194
|
+
# t1.enq 0
|
|
1195
|
+
# app.run
|
|
1196
|
+
# end
|
|
1197
|
+
#
|
|
1198
|
+
# assert_equal [0,1,1], runlist
|
|
1199
|
+
# assert_audit_equal(ExpAudit[[nil,0],[t1,1],[t2,2]], app._results(t2).first)
|
|
1200
|
+
# assert_audit_equal(ExpAudit[[nil,0],[t1,1],[t3,2]], app._results(t3).first)
|
|
1201
|
+
# end
|
|
1202
|
+
|
|
1203
|
+
#
|
|
1204
|
+
# sequence tests
|
|
1205
|
+
#
|
|
1206
|
+
|
|
1207
|
+
def test_run_sequence
|
|
1208
|
+
t1 = Task.new(&add_one)
|
|
1209
|
+
t2 = Task.new(&add_one)
|
|
1210
|
+
|
|
1211
|
+
app.sequence(t1,t2)
|
|
1212
|
+
with_options :debug => true do
|
|
1213
|
+
t1.enq 0
|
|
1214
|
+
app.run
|
|
1089
1215
|
end
|
|
1216
|
+
|
|
1217
|
+
assert_equal [0,1], runlist
|
|
1218
|
+
assert_audit_equal(ExpAudit[[nil,0],[t1,1],[t2,2]], app._results(t2).first)
|
|
1219
|
+
end
|
|
1090
1220
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
4 => [[nil,3], [t2,4], [t3,5]],
|
|
1106
|
-
5 => [[nil,4], [t2,5], [t3,6]])
|
|
1107
|
-
end
|
|
1108
|
-
|
|
1109
|
-
#
|
|
1110
|
-
# run batched task tests
|
|
1111
|
-
#
|
|
1112
|
-
|
|
1113
|
-
def test_run_batched_task
|
|
1114
|
-
t1 = Task.new('addition_template') do |task, input|
|
|
1115
|
-
runlist << input
|
|
1116
|
-
input + task.config[:factor0] + task.config[:factor1]
|
|
1117
|
-
end
|
|
1118
|
-
assert_equal 2, t1.batch.length
|
|
1119
|
-
|
|
1120
|
-
t1_0 = t1.batch[0]
|
|
1121
|
-
t1_1 = t1.batch[1]
|
|
1122
|
-
|
|
1123
|
-
assert_equal [0, 10], [t1_0.config[:factor0], t1_0.config[:factor1]]
|
|
1124
|
-
assert_equal [1, 20], [t1_1.config[:factor0], t1_1.config[:factor1]]
|
|
1125
|
-
|
|
1126
|
-
app.run(t1,1,2,3)
|
|
1127
|
-
|
|
1128
|
-
# note same inputs fed to each template
|
|
1129
|
-
assert_equal [1,2,3, 1,2,3], runlist
|
|
1130
|
-
assert_audits(t1_0.results,
|
|
1131
|
-
0 => [[nil,1], [t1_0,11]],
|
|
1132
|
-
1 => [[nil,2], [t1_0,12]],
|
|
1133
|
-
2 => [[nil,3], [t1_0,13]])
|
|
1134
|
-
assert_audits(t1_1.results,
|
|
1135
|
-
0 => [[nil,1], [t1_1,22]],
|
|
1136
|
-
1 => [[nil,2], [t1_1,23]],
|
|
1137
|
-
2 => [[nil,3], [t1_1,24]])
|
|
1138
|
-
end
|
|
1221
|
+
def test_run_sequence_from_trailing_task
|
|
1222
|
+
t1 = Task.new(&add_one)
|
|
1223
|
+
t2 = Task.new(&add_one)
|
|
1224
|
+
|
|
1225
|
+
app.sequence(t1,t2)
|
|
1226
|
+
with_options :debug => true do
|
|
1227
|
+
t2.enq 1
|
|
1228
|
+
app.run
|
|
1229
|
+
end
|
|
1230
|
+
|
|
1231
|
+
assert_equal [1], runlist
|
|
1232
|
+
assert_equal 0, app._results(t1).length
|
|
1233
|
+
assert_audit_equal(ExpAudit[[nil,1],[t2,2]], app._results(t2).first)
|
|
1234
|
+
end
|
|
1139
1235
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1236
|
+
#
|
|
1237
|
+
# fork tests
|
|
1238
|
+
#
|
|
1239
|
+
|
|
1240
|
+
def test_run_fork
|
|
1241
|
+
t1 = Task.new(&add_one)
|
|
1242
|
+
t2 = Task.new(&add_one)
|
|
1243
|
+
t3 = Task.new(&add_one)
|
|
1244
|
+
|
|
1245
|
+
app.fork(t1, t2, t3)
|
|
1246
|
+
with_options :debug => true do
|
|
1247
|
+
t1.enq 0
|
|
1248
|
+
app.run
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
assert_equal [0,1,1], runlist
|
|
1252
|
+
assert_audit_equal(ExpAudit[[nil,0],[t1,1],[t2,2]], app._results(t2).first)
|
|
1253
|
+
assert_audit_equal(ExpAudit[[nil,0],[t1,1],[t3,2]], app._results(t3).first)
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
#
|
|
1257
|
+
# merge tests
|
|
1258
|
+
#
|
|
1259
|
+
|
|
1260
|
+
def test_run_merge
|
|
1261
|
+
t1 = Task.new(&add_one)
|
|
1262
|
+
t2 = Task.new(&add_one)
|
|
1263
|
+
t3 = Task.new(&add_one)
|
|
1264
|
+
|
|
1265
|
+
app.merge(t3, t1, t2)
|
|
1266
|
+
with_options :debug => true do
|
|
1267
|
+
t1.enq 0
|
|
1268
|
+
t2.enq 10
|
|
1269
|
+
app.run
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
assert_equal [0,10,1,11], runlist
|
|
1273
|
+
|
|
1274
|
+
assert_audits_equal([
|
|
1275
|
+
ExpAudit[[nil,0],[t1,1],[t3,2]],
|
|
1276
|
+
ExpAudit[[nil,10],[t2,11],[t3,12]]
|
|
1277
|
+
], app._results(t3))
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1280
|
+
#
|
|
1281
|
+
# run batched task tests
|
|
1282
|
+
#
|
|
1283
|
+
|
|
1284
|
+
def test_run_batched_task
|
|
1285
|
+
t1 = Task.new('template') do |task, input|
|
|
1286
|
+
runlist << input
|
|
1287
|
+
input + task.config[:factor]
|
|
1288
|
+
end
|
|
1289
|
+
assert_equal 2, t1.batch.length
|
|
1290
|
+
|
|
1291
|
+
t1_0 = t1.batch[0]
|
|
1292
|
+
t1_1 = t1.batch[1]
|
|
1293
|
+
|
|
1294
|
+
assert_equal 10, t1_0.config[:factor]
|
|
1295
|
+
assert_equal 22, t1_1.config[:factor]
|
|
1296
|
+
|
|
1297
|
+
with_options :debug => true do
|
|
1298
|
+
t1.enq 0
|
|
1299
|
+
app.run
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
# note same input fed to each template
|
|
1303
|
+
assert_equal [0,0], runlist
|
|
1304
|
+
|
|
1305
|
+
assert_audits_equal([
|
|
1306
|
+
ExpAudit[[nil,0],[t1_0,10]],
|
|
1307
|
+
ExpAudit[[nil,0],[t1_1,22]]
|
|
1308
|
+
], app._results(*t1.batch))
|
|
1309
|
+
end
|
|
1310
|
+
|
|
1311
|
+
def test_run_batched_task_with_existing_audit_trails
|
|
1312
|
+
t1 = Task.new('template') do |task, input|
|
|
1313
|
+
runlist << input
|
|
1314
|
+
input + task.config[:factor]
|
|
1315
|
+
end
|
|
1316
|
+
assert_equal 2, t1.batch.length
|
|
1317
|
+
|
|
1318
|
+
t1_0 = t1.batch[0]
|
|
1319
|
+
t1_1 = t1.batch[1]
|
|
1320
|
+
|
|
1321
|
+
assert_equal 10, t1_0.config[:factor]
|
|
1322
|
+
assert_equal 22, t1_1.config[:factor]
|
|
1323
|
+
|
|
1324
|
+
a = Support::Audit.new(0, :a)
|
|
1325
|
+
with_options :debug => true do
|
|
1326
|
+
t1.enq a
|
|
1327
|
+
app.run
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
# note same input fed to each template
|
|
1331
|
+
assert_equal [0,0], runlist
|
|
1332
|
+
|
|
1333
|
+
assert_audits_equal([
|
|
1334
|
+
ExpAudit[[:a,0],[t1_0,10]],
|
|
1335
|
+
ExpAudit[[:a,0],[t1_1,22]]
|
|
1336
|
+
], app._results(t1.batch))
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
# TODO -- JRuby inconsistent test
|
|
1340
|
+
# RESOLVED? 2007/01/30
|
|
1341
|
+
def test_multithread_batched_tasks_execute_cosynchronously
|
|
1172
1342
|
extended_test do
|
|
1343
|
+
lock = Monitor.new
|
|
1173
1344
|
max_threads = 0
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1345
|
+
n_threads = 0
|
|
1346
|
+
|
|
1347
|
+
block = lambda do |task|
|
|
1348
|
+
lock.synchronize do
|
|
1349
|
+
n_threads += 1
|
|
1350
|
+
max_threads = n_threads if n_threads > max_threads
|
|
1351
|
+
end
|
|
1179
1352
|
|
|
1180
1353
|
# sleep is necessary so the other threads
|
|
1181
1354
|
# have an opportunity to execute
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1355
|
+
sleep(0.1)
|
|
1356
|
+
|
|
1357
|
+
lock.synchronize { n_threads -= 1 }
|
|
1358
|
+
nil
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
t1 = Task.new(&block)
|
|
1362
|
+
t1.initialize_batch_obj
|
|
1363
|
+
|
|
1364
|
+
assert_equal 2, t1.batch.length
|
|
1365
|
+
t1.multithread = true
|
|
1366
|
+
t1.enq
|
|
1367
|
+
|
|
1368
|
+
with_options :debug => true do
|
|
1369
|
+
app.run
|
|
1370
|
+
end
|
|
1371
|
+
assert_equal 2, max_threads
|
|
1198
1372
|
end
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
def test_feedback_loop
|
|
1304
|
-
t1 = Task.new(&add_one)
|
|
1305
|
-
t2 = Task.new(&add_one)
|
|
1306
|
-
t3 = Task.new(&add_one)
|
|
1307
|
-
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
def test_fork_in_batched_task
|
|
1376
|
+
t1, t2, t3 = Array.new(3) do
|
|
1377
|
+
t = Task.new(nil, :factor => 10) do |task, input|
|
|
1378
|
+
runlist << input
|
|
1379
|
+
input + task.config[:factor]
|
|
1380
|
+
end
|
|
1381
|
+
t.initialize_batch_obj(nil, :factor => 22)
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1384
|
+
app.fork(t1, t2, t3)
|
|
1385
|
+
with_options :debug => true do
|
|
1386
|
+
t1.enq 0
|
|
1387
|
+
app.run
|
|
1388
|
+
end
|
|
1389
|
+
|
|
1390
|
+
assert_equal [
|
|
1391
|
+
0,0, # once for each t1 template
|
|
1392
|
+
10,10, 10,10, # first result into t2, t3 tasks
|
|
1393
|
+
22,22, 22,22 # second result into t2, t3 tasks
|
|
1394
|
+
], runlist
|
|
1395
|
+
|
|
1396
|
+
t1_0 = t1.batch[0]
|
|
1397
|
+
t1_1 = t1.batch[1]
|
|
1398
|
+
|
|
1399
|
+
t2_0 = t2.batch[0]
|
|
1400
|
+
t2_1 = t2.batch[1]
|
|
1401
|
+
|
|
1402
|
+
t3_0 = t3.batch[0]
|
|
1403
|
+
t3_1 = t3.batch[1]
|
|
1404
|
+
|
|
1405
|
+
# check t2 results
|
|
1406
|
+
assert_audits_equal([
|
|
1407
|
+
ExpAudit[[nil,0],[t1_0,10],[t2_0,20]],
|
|
1408
|
+
ExpAudit[[nil,0],[t1_1,22],[t2_0,32]],
|
|
1409
|
+
ExpAudit[[nil,0],[t1_0,10],[t2_1,32]],
|
|
1410
|
+
ExpAudit[[nil,0],[t1_1,22],[t2_1,44]]
|
|
1411
|
+
], app._results(t2.batch))
|
|
1412
|
+
|
|
1413
|
+
# check t3 results
|
|
1414
|
+
assert_audits_equal([
|
|
1415
|
+
ExpAudit[[nil,0],[t1_0,10],[t3_0,20]],
|
|
1416
|
+
ExpAudit[[nil,0],[t1_1,22],[t3_0,32]],
|
|
1417
|
+
ExpAudit[[nil,0],[t1_0,10],[t3_1,32]],
|
|
1418
|
+
ExpAudit[[nil,0],[t1_1,22],[t3_1,44]]
|
|
1419
|
+
], app._results(t3.batch))
|
|
1420
|
+
end
|
|
1421
|
+
|
|
1422
|
+
def test_merge_batched_task
|
|
1423
|
+
t1, t2, t3 = Array.new(3) do
|
|
1424
|
+
t = Task.new(nil, :factor => 10) do |task, input|
|
|
1425
|
+
runlist << input
|
|
1426
|
+
input + task.config[:factor]
|
|
1427
|
+
end
|
|
1428
|
+
t.initialize_batch_obj(nil, :factor => 22)
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
app.merge(t3, t1, t2)
|
|
1432
|
+
t1.enq(0)
|
|
1433
|
+
t2.enq(2)
|
|
1434
|
+
with_options :debug => true do
|
|
1435
|
+
app.run
|
|
1436
|
+
end
|
|
1437
|
+
|
|
1438
|
+
assert_equal [
|
|
1439
|
+
0,0, # 1 input to each t1
|
|
1440
|
+
2,2, # 2 input to each t2
|
|
1441
|
+
10,10,22,22, # t1 outputs to each t3
|
|
1442
|
+
12,12,24,24 # t2 outputs to each t3
|
|
1443
|
+
], runlist
|
|
1444
|
+
|
|
1445
|
+
t1_0 = t1.batch[0]
|
|
1446
|
+
t1_1 = t1.batch[1]
|
|
1447
|
+
|
|
1448
|
+
t2_0 = t2.batch[0]
|
|
1449
|
+
t2_1 = t2.batch[1]
|
|
1450
|
+
|
|
1451
|
+
t3_0 = t3.batch[0]
|
|
1452
|
+
t3_1 = t3.batch[1]
|
|
1453
|
+
|
|
1454
|
+
# check results
|
|
1455
|
+
assert_audits_equal([
|
|
1456
|
+
ExpAudit[[nil,0],[t1_0,10],[t3_0,20]],
|
|
1457
|
+
ExpAudit[[nil,0],[t1_1,22],[t3_0,32]],
|
|
1458
|
+
ExpAudit[[nil,2],[t2_0,12],[t3_0,22]],
|
|
1459
|
+
ExpAudit[[nil,2],[t2_1,24],[t3_0,34]],
|
|
1460
|
+
ExpAudit[[nil,0],[t1_0,10],[t3_1,32]],
|
|
1461
|
+
ExpAudit[[nil,0],[t1_1,22],[t3_1,44]],
|
|
1462
|
+
ExpAudit[[nil,2],[t2_0,12],[t3_1,34]],
|
|
1463
|
+
ExpAudit[[nil,2],[t2_1,24],[t3_1,46]]
|
|
1464
|
+
], app._results(t3.batch))
|
|
1465
|
+
end
|
|
1466
|
+
|
|
1467
|
+
#
|
|
1468
|
+
# other run tests
|
|
1469
|
+
#
|
|
1470
|
+
|
|
1471
|
+
def test_feedback_loop
|
|
1472
|
+
t1 = Task.new(&add_one)
|
|
1473
|
+
t2 = Task.new(&add_one)
|
|
1474
|
+
t3 = Task.new(&add_one)
|
|
1475
|
+
|
|
1308
1476
|
# distribute the results of t1 based on value
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
end
|
|
1318
|
-
|
|
1477
|
+
t1.on_complete do |result|
|
|
1478
|
+
if result._current < 4
|
|
1479
|
+
t2.enq result
|
|
1480
|
+
else
|
|
1481
|
+
t3.enq result
|
|
1482
|
+
end
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1319
1485
|
# set the results of t2 to reinvoke the workflow
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
assert_audits(t3_results,
|
|
1331
|
-
0 => [[nil,3], [t1,4], [t3,5]],
|
|
1332
|
-
1 => [[nil,1], [t1,2], [t2,3], [t1,4], [t3,5]],
|
|
1333
|
-
2 => [[nil,2], [t1,3], [t2,4], [t1,5], [t3,6]])
|
|
1334
|
-
end
|
|
1335
|
-
|
|
1336
|
-
#
|
|
1337
|
-
# synchronization tests
|
|
1338
|
-
#
|
|
1339
|
-
|
|
1340
|
-
def BREAK_DOES_NOT_ACTUALLY_TEST_THIStest_run_is_synchronized
|
|
1341
|
-
extended_test do
|
|
1342
|
-
count = 0
|
|
1343
|
-
counter = Task.new do
|
|
1344
|
-
count += 1
|
|
1345
|
-
end
|
|
1346
|
-
|
|
1347
|
-
t1 = Thread.new { 10000.times { app.run(counter, nil) } }
|
|
1348
|
-
t2 = Thread.new { 10000.times { app.run(counter, nil) } }
|
|
1349
|
-
t1.join
|
|
1350
|
-
t2.join
|
|
1351
|
-
|
|
1352
|
-
assert_equal 20000, count
|
|
1353
|
-
end
|
|
1354
|
-
end
|
|
1486
|
+
app.sequence(t2, t1)
|
|
1487
|
+
|
|
1488
|
+
with_options :debug => true do
|
|
1489
|
+
t1.enq(0)
|
|
1490
|
+
t1.enq(2)
|
|
1491
|
+
app.run
|
|
1492
|
+
end
|
|
1493
|
+
|
|
1494
|
+
assert_equal [0,2,1,3,2,4,3,5,4,5], runlist
|
|
1355
1495
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
end
|
|
1366
|
-
|
|
1367
|
-
def test_task_can_queue_from_within_threaded_and_unthreaded_tasks
|
|
1368
|
-
threaded_count = 0
|
|
1369
|
-
threaded = Task.new do
|
|
1370
|
-
runlist << "t"
|
|
1371
|
-
threaded_count += 1
|
|
1372
|
-
threaded.enq nil if threaded_count < 3
|
|
1373
|
-
end
|
|
1374
|
-
|
|
1375
|
-
not_threaded_count = 0
|
|
1376
|
-
not_threaded = Task.new do
|
|
1377
|
-
runlist << "n"
|
|
1378
|
-
not_threaded_count += 1
|
|
1379
|
-
not_threaded.enq nil if not_threaded_count < 3
|
|
1380
|
-
end
|
|
1381
|
-
|
|
1382
|
-
app.multithread(threaded)
|
|
1383
|
-
threaded.enq nil
|
|
1384
|
-
not_threaded.enq nil
|
|
1496
|
+
assert_audits_equal([
|
|
1497
|
+
ExpAudit[[nil,2],[t1,3],[t2,4],[t1,5],[t3,6]],
|
|
1498
|
+
ExpAudit[[nil,0],[t1,1],[t2,2],[t1,3],[t2,4],[t1,5],[t3,6]]
|
|
1499
|
+
], app._results(t3.batch))
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
#
|
|
1503
|
+
# _results test
|
|
1504
|
+
#
|
|
1385
1505
|
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
#
|
|
1401
|
-
#
|
|
1402
|
-
#
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1506
|
+
def test__results_returns_audited_results_for_listed_sources
|
|
1507
|
+
t1 = Task.new {|task, input| input + 1 }
|
|
1508
|
+
a1 = t1._execute(0)
|
|
1509
|
+
|
|
1510
|
+
t2 = Task.new {|task, input| input + 1 }
|
|
1511
|
+
a2 = t2._execute(1)
|
|
1512
|
+
|
|
1513
|
+
app.aggregator.store a1
|
|
1514
|
+
app.aggregator.store a2
|
|
1515
|
+
assert_equal [a1], app._results(t1)
|
|
1516
|
+
assert_equal [a2, a1], app._results(t2, t1)
|
|
1517
|
+
assert_equal [a1, a1], app._results(t1, t1)
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
#
|
|
1521
|
+
# results test
|
|
1522
|
+
#
|
|
1523
|
+
|
|
1524
|
+
def test_results_documentation
|
|
1525
|
+
t1 = Task.new {|task, input| input += 1 }
|
|
1526
|
+
t2 = Task.new {|task, input| input += 10 }
|
|
1527
|
+
t3 = t2.initialize_batch_obj
|
|
1528
|
+
|
|
1529
|
+
t1.enq(0)
|
|
1530
|
+
t2.enq(1)
|
|
1531
|
+
|
|
1532
|
+
app.run
|
|
1533
|
+
assert_equal [1, 11, 11], app.results(t1, t2.batch)
|
|
1534
|
+
assert_equal [11, 1], app.results(t2, t1)
|
|
1535
|
+
end
|
|
1536
|
+
|
|
1537
|
+
def test_results_returns_current_values_of__results
|
|
1538
|
+
t1 = Task.new {|task, input| input + 1 }
|
|
1539
|
+
a1 = t1._execute(0)
|
|
1540
|
+
|
|
1541
|
+
t2 = Task.new {|task, input| input + 1 }
|
|
1542
|
+
a2 = t2._execute(1)
|
|
1543
|
+
|
|
1544
|
+
app.aggregator.store a1
|
|
1545
|
+
app.aggregator.store a2
|
|
1546
|
+
assert_equal [1], app.results(t1)
|
|
1547
|
+
assert_equal [2, 1], app.results(t2, t1)
|
|
1548
|
+
assert_equal [1, 1], app.results(t1, t1)
|
|
1549
|
+
end
|
|
1550
|
+
|
|
1551
|
+
def test_results_for_various_objects
|
|
1552
|
+
t1 = Task.new {|task, input| input}
|
|
1421
1553
|
|
|
1554
|
+
t1.enq({:key => 'value'})
|
|
1555
|
+
t1.enq([1,2,3])
|
|
1556
|
+
t1.enq(2)
|
|
1557
|
+
t1.enq("str")
|
|
1558
|
+
|
|
1559
|
+
app.run
|
|
1560
|
+
assert_equal [{:key => 'value'}, [1,2,3], 2, "str"], app.results(t1)
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1563
|
+
#
|
|
1564
|
+
# synchronization tests
|
|
1565
|
+
#
|
|
1566
|
+
|
|
1567
|
+
def test_task_may_be_queued_from_task_while_task_is_running
|
|
1568
|
+
count = 0
|
|
1569
|
+
counter = Task.new do |task|
|
|
1570
|
+
count += 1
|
|
1571
|
+
counter.enq if count < 3
|
|
1572
|
+
end
|
|
1573
|
+
|
|
1574
|
+
with_options :debug => true do
|
|
1575
|
+
counter.enq
|
|
1576
|
+
app.run
|
|
1577
|
+
end
|
|
1578
|
+
|
|
1579
|
+
assert_equal 3, count
|
|
1580
|
+
end
|
|
1581
|
+
|
|
1582
|
+
def test_task_can_queue_from_within_threaded_and_unthreaded_tasks
|
|
1583
|
+
threaded_count = 0
|
|
1584
|
+
threaded = Task.new do |task|
|
|
1585
|
+
runlist << "t"
|
|
1586
|
+
threaded_count += 1
|
|
1587
|
+
threaded.enq if threaded_count < 3
|
|
1588
|
+
end
|
|
1589
|
+
|
|
1590
|
+
not_threaded_count = 0
|
|
1591
|
+
not_threaded = Task.new do |task|
|
|
1592
|
+
runlist << "n"
|
|
1593
|
+
not_threaded_count += 1
|
|
1594
|
+
not_threaded.enq if not_threaded_count < 3
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
threaded.multithread = true
|
|
1598
|
+
threaded.enq
|
|
1599
|
+
not_threaded.enq
|
|
1600
|
+
|
|
1601
|
+
with_options :debug => true do
|
|
1602
|
+
app.run
|
|
1603
|
+
end
|
|
1604
|
+
|
|
1605
|
+
assert_equal [
|
|
1606
|
+
"t", "n",
|
|
1607
|
+
"t", "n",
|
|
1608
|
+
"t", "n"], runlist
|
|
1609
|
+
assert_equal 3, threaded_count
|
|
1610
|
+
assert_equal 3, not_threaded_count
|
|
1611
|
+
end
|
|
1612
|
+
|
|
1422
1613
|
def test_run_is_allowed_within_non_threaded_task
|
|
1423
|
-
# run within a threaded task deadlocks
|
|
1424
1614
|
t2 = Task.new(&add_one)
|
|
1425
1615
|
t1 = Task.new do |task, input|
|
|
1426
1616
|
runlist << input
|
|
1427
|
-
|
|
1428
|
-
|
|
1617
|
+
t2.enq input
|
|
1618
|
+
app.run
|
|
1619
|
+
|
|
1429
1620
|
input += 1
|
|
1430
1621
|
end
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1622
|
+
|
|
1623
|
+
with_options :debug => true do
|
|
1624
|
+
t1.enq 0
|
|
1625
|
+
app.run
|
|
1626
|
+
end
|
|
1627
|
+
|
|
1628
|
+
assert_equal [0,0], runlist
|
|
1629
|
+
assert_audit_equal(ExpAudit[[nil,0],[t1,1]], app._results(t1).first)
|
|
1630
|
+
assert_audit_equal(ExpAudit[[nil,0],[t2,1]], app._results(t2).first)
|
|
1631
|
+
end
|
|
1632
|
+
|
|
1633
|
+
def test_run_is_allowed_within_threaded_task
|
|
1634
|
+
t2 = Task.new(&add_one)
|
|
1635
|
+
t1 = Task.new do |task, input|
|
|
1636
|
+
runlist << input
|
|
1637
|
+
t2.enq input
|
|
1638
|
+
app.run
|
|
1639
|
+
|
|
1640
|
+
input += 1
|
|
1641
|
+
end
|
|
1642
|
+
|
|
1643
|
+
t1.multithread = true
|
|
1644
|
+
t2.multithread = true
|
|
1645
|
+
with_options :debug => true do
|
|
1646
|
+
t1.enq 0
|
|
1647
|
+
app.run
|
|
1648
|
+
end
|
|
1649
|
+
|
|
1650
|
+
assert_equal [0,0], runlist
|
|
1651
|
+
assert_audit_equal(ExpAudit[[nil,0],[t1,1]], app._results(t1).first)
|
|
1652
|
+
assert_audit_equal(ExpAudit[[nil,0],[t2,1]], app._results(t2).first)
|
|
1653
|
+
end
|
|
1654
|
+
|
|
1447
1655
|
#
|
|
1448
1656
|
# error tests
|
|
1449
1657
|
#
|
|
@@ -1455,36 +1663,39 @@ class AppTest < Test::Unit::TestCase
|
|
|
1455
1663
|
end
|
|
1456
1664
|
|
|
1457
1665
|
def test_unhandled_exception_on_main_thread_is_logged_by_default
|
|
1458
|
-
|
|
1666
|
+
task = Task.new {|t| raise "error"}
|
|
1459
1667
|
|
|
1460
1668
|
string = set_stringio_logger
|
|
1461
|
-
|
|
1669
|
+
task.enq
|
|
1670
|
+
app.run
|
|
1462
1671
|
|
|
1463
1672
|
assert string =~ /RuntimeError error/
|
|
1464
1673
|
end
|
|
1465
1674
|
|
|
1466
1675
|
def test_unhandled_exception_raises_run_error_on_main_thread_when_debug
|
|
1467
|
-
|
|
1676
|
+
task = Task.new {|t| raise "error"}
|
|
1468
1677
|
|
|
1469
1678
|
with_options :debug => true do
|
|
1470
1679
|
begin
|
|
1471
|
-
|
|
1680
|
+
task.enq
|
|
1681
|
+
app.run
|
|
1472
1682
|
flunk "no error was raised"
|
|
1473
1683
|
rescue
|
|
1474
1684
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1685
|
+
assert_equal 1 , $!.errors.length
|
|
1686
|
+
assert $!.errors[0].kind_of?(RuntimeError)
|
|
1687
|
+
assert_equal "error", $!.errors[0].message
|
|
1478
1688
|
end
|
|
1479
|
-
|
|
1689
|
+
end
|
|
1480
1690
|
end
|
|
1481
1691
|
|
|
1482
1692
|
def test_unhandled_exception_on_thread_is_logged_by_default
|
|
1483
|
-
|
|
1484
|
-
|
|
1693
|
+
task = Task.new {|t| raise "error"}
|
|
1694
|
+
task.multithread = true
|
|
1485
1695
|
|
|
1486
1696
|
string = set_stringio_logger
|
|
1487
|
-
|
|
1697
|
+
task.enq
|
|
1698
|
+
app.run
|
|
1488
1699
|
|
|
1489
1700
|
assert string =~ /RuntimeError error/
|
|
1490
1701
|
end
|
|
@@ -1492,103 +1703,115 @@ class AppTest < Test::Unit::TestCase
|
|
|
1492
1703
|
# Ruby inconsistent test
|
|
1493
1704
|
# <"error"> expected but was
|
|
1494
1705
|
# <"Tap::App::TerminateError">.
|
|
1706
|
+
# RESOLVED? -- 2008/01/29
|
|
1707
|
+
#
|
|
1495
1708
|
def test_unhandled_exception_raises_run_error_on_thread_when_debug
|
|
1496
|
-
|
|
1497
|
-
|
|
1709
|
+
task = Task.new {|t| raise "error"}
|
|
1710
|
+
task.multithread = true
|
|
1498
1711
|
|
|
1499
1712
|
with_options :debug => true do
|
|
1500
1713
|
begin
|
|
1501
|
-
|
|
1714
|
+
task.enq
|
|
1715
|
+
app.run
|
|
1502
1716
|
flunk "no error was raised"
|
|
1503
1717
|
rescue
|
|
1504
1718
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1719
|
+
assert_equal 1 , $!.errors.length
|
|
1720
|
+
assert $!.errors[0].kind_of?(RuntimeError)
|
|
1721
|
+
assert_equal "error", $!.errors[0].message
|
|
1508
1722
|
end
|
|
1509
|
-
|
|
1723
|
+
end
|
|
1510
1724
|
end
|
|
1511
1725
|
|
|
1512
|
-
# TODO -- REWORD
|
|
1513
|
-
|
|
1514
1726
|
# Ruby inconsistent test
|
|
1515
1727
|
# <"error"> expected but was
|
|
1516
1728
|
# <"Tap::App::TerminateError">.
|
|
1729
|
+
# RESOLVED? -- 2008/01/29
|
|
1730
|
+
#
|
|
1517
1731
|
def test_unhandled_exception_on_thread_teminates_threads
|
|
1518
1732
|
extended_test do
|
|
1519
1733
|
count = 0
|
|
1520
1734
|
terminated_count = 0
|
|
1521
1735
|
|
|
1522
1736
|
tasks = Array.new(2) do
|
|
1523
|
-
Task.new do |t
|
|
1737
|
+
Task.new do |t|
|
|
1524
1738
|
# count to make sure the tasks actually executed
|
|
1525
1739
|
count += 1
|
|
1526
1740
|
|
|
1527
1741
|
terminated_count += 1
|
|
1528
|
-
sleep
|
|
1742
|
+
sleep 0.8
|
|
1529
1743
|
t.check_terminate
|
|
1530
1744
|
|
|
1531
1745
|
# this should not happen
|
|
1532
1746
|
terminated_count -= 1
|
|
1533
1747
|
end
|
|
1534
1748
|
end
|
|
1535
|
-
terr = Task.new {|t
|
|
1749
|
+
terr = Task.new {|t| raise "error"}
|
|
1536
1750
|
|
|
1537
1751
|
tasks << terr
|
|
1538
1752
|
tasks.each do |task|
|
|
1539
1753
|
task.multithread = true
|
|
1540
|
-
task.enq
|
|
1754
|
+
task.enq
|
|
1541
1755
|
end
|
|
1542
|
-
|
|
1756
|
+
|
|
1543
1757
|
with_options :debug => true do
|
|
1544
1758
|
begin
|
|
1545
1759
|
app.run
|
|
1546
1760
|
flunk "no error was raised"
|
|
1547
1761
|
rescue
|
|
1548
1762
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1763
|
+
assert_equal 1 , $!.errors.length
|
|
1764
|
+
assert $!.errors[0].kind_of?(RuntimeError)
|
|
1765
|
+
assert_equal "error", $!.errors[0].message
|
|
1552
1766
|
end
|
|
1553
|
-
|
|
1554
|
-
|
|
1767
|
+
end
|
|
1768
|
+
|
|
1555
1769
|
assert_equal 2, count
|
|
1556
1770
|
assert_equal 2, terminated_count
|
|
1557
1771
|
end
|
|
1558
1772
|
end
|
|
1559
|
-
|
|
1773
|
+
|
|
1560
1774
|
# Ruby inconsistent test
|
|
1561
1775
|
# <"error"> expected but was
|
|
1562
1776
|
# <"Tap::App::TerminateError">.
|
|
1563
1777
|
#
|
|
1564
1778
|
# <"term error 0"> expected but was
|
|
1565
1779
|
# <"term error 1">.
|
|
1780
|
+
# RESOLVED? -- 2008/01/29
|
|
1566
1781
|
#
|
|
1567
1782
|
# JRuby inconsistent test
|
|
1783
|
+
# RESOLVED? -- 2008/01/30
|
|
1784
|
+
#
|
|
1568
1785
|
def test_exceptions_from_handling_termination_error_are_collected
|
|
1569
1786
|
extended_test do
|
|
1787
|
+
lock = Monitor.new
|
|
1570
1788
|
count = 0
|
|
1571
1789
|
count_in_threaded_error_handling = 0
|
|
1572
1790
|
|
|
1573
1791
|
tasks = Array.new(2) do
|
|
1574
|
-
Task.new do |t
|
|
1575
|
-
n =
|
|
1576
|
-
|
|
1792
|
+
Task.new do |t|
|
|
1793
|
+
n = nil
|
|
1794
|
+
lock.synchronize do
|
|
1795
|
+
n = count
|
|
1577
1796
|
count += 1
|
|
1578
|
-
|
|
1797
|
+
end
|
|
1798
|
+
|
|
1799
|
+
sleep 0.8
|
|
1800
|
+
|
|
1801
|
+
begin
|
|
1579
1802
|
t.check_terminate
|
|
1580
1803
|
rescue
|
|
1581
|
-
count_in_threaded_error_handling += 1
|
|
1804
|
+
lock.synchronize { count_in_threaded_error_handling += 1 }
|
|
1582
1805
|
raise "term error #{n}"
|
|
1583
1806
|
end
|
|
1584
1807
|
end
|
|
1585
1808
|
end
|
|
1586
|
-
terr = Task.new {|t
|
|
1809
|
+
terr = Task.new {|t| raise "error"}
|
|
1587
1810
|
|
|
1588
1811
|
tasks << terr
|
|
1589
1812
|
tasks.each do |task|
|
|
1590
1813
|
task.multithread = true
|
|
1591
|
-
task.enq
|
|
1814
|
+
task.enq
|
|
1592
1815
|
end
|
|
1593
1816
|
|
|
1594
1817
|
with_options :debug => true do
|
|
@@ -1597,20 +1820,30 @@ class AppTest < Test::Unit::TestCase
|
|
|
1597
1820
|
flunk "no error was raised"
|
|
1598
1821
|
rescue
|
|
1599
1822
|
assert $!.kind_of?(Tap::Support::RunError)
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
assert_equal
|
|
1604
|
-
|
|
1605
|
-
$!.terminate_errors.each_with_index do |term_err, i|
|
|
1606
|
-
assert term_err.kind_of?(RuntimeError)
|
|
1607
|
-
assert_equal "term error #{i}", term_err.message
|
|
1608
|
-
end
|
|
1823
|
+
assert_equal 3, $!.errors.length
|
|
1824
|
+
$!.errors.each {|error| assert error.kind_of?(RuntimeError) }
|
|
1825
|
+
messages = $!.errors.collect {|error| error.message}.sort
|
|
1826
|
+
assert_equal ["error", "term error 0", "term error 1"], messages
|
|
1609
1827
|
end
|
|
1610
|
-
|
|
1828
|
+
|
|
1611
1829
|
assert_equal 2, count
|
|
1612
1830
|
assert_equal 2, count_in_threaded_error_handling
|
|
1613
1831
|
end
|
|
1614
1832
|
end
|
|
1615
1833
|
end
|
|
1834
|
+
|
|
1835
|
+
#
|
|
1836
|
+
# benchmarks
|
|
1837
|
+
#
|
|
1838
|
+
|
|
1839
|
+
def test_run_speed
|
|
1840
|
+
t = Tap::Task.new
|
|
1841
|
+
benchmark_test(20) do |x|
|
|
1842
|
+
n = 10000
|
|
1843
|
+
|
|
1844
|
+
x.report("10k enq ") { n.times { t.enq(1) } }
|
|
1845
|
+
x.report("10k run ") { n.times {}; app.run }
|
|
1846
|
+
x.report("10k _execute ") { n.times { t._execute(1) } }
|
|
1847
|
+
end
|
|
1848
|
+
end
|
|
1616
1849
|
end
|