basechip 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/.document +5 -0
  2. data/Gemfile +20 -0
  3. data/Gemfile.lock +32 -0
  4. data/LICENSE.txt +14 -0
  5. data/README.rdoc +19 -0
  6. data/VERSION +1 -0
  7. data/bin/basechip +25 -0
  8. data/collateral/block/block.rb.erb +20 -0
  9. data/collateral/configuration/configuration.rb.erb +19 -0
  10. data/collateral/project/Gemfile +19 -0
  11. data/collateral/project/gitignore +6 -0
  12. data/collateral/project/project.rb.erb +76 -0
  13. data/collateral/project/settings.rb.erb +26 -0
  14. data/collateral/recipes/icarus.rb +73 -0
  15. data/collateral/recipes/icarus.rb.erb +88 -0
  16. data/collateral/recipes/local_cluster.rb +27 -0
  17. data/lib/array.rb +26 -0
  18. data/lib/base_chip/action.rb +309 -0
  19. data/lib/base_chip/base.rb +105 -0
  20. data/lib/base_chip/block.rb +75 -0
  21. data/lib/base_chip/bom.rb +75 -0
  22. data/lib/base_chip/bom_file.rb +45 -0
  23. data/lib/base_chip/cli.rb +371 -0
  24. data/lib/base_chip/cluster.rb +93 -0
  25. data/lib/base_chip/cluster_type.rb +45 -0
  26. data/lib/base_chip/code_area.rb +30 -0
  27. data/lib/base_chip/configuration.rb +257 -0
  28. data/lib/base_chip/dsl.rb +593 -0
  29. data/lib/base_chip/exit_error.rb +20 -0
  30. data/lib/base_chip/generator_menu.rb +64 -0
  31. data/lib/base_chip/git.rb +32 -0
  32. data/lib/base_chip/hierarchy.rb +84 -0
  33. data/lib/base_chip/install_menu.rb +89 -0
  34. data/lib/base_chip/ipc.rb +50 -0
  35. data/lib/base_chip/list_menu.rb +134 -0
  36. data/lib/base_chip/menu.rb +70 -0
  37. data/lib/base_chip/out_file.rb +68 -0
  38. data/lib/base_chip/permutation.rb +26 -0
  39. data/lib/base_chip/permute.rb +25 -0
  40. data/lib/base_chip/post.rb +26 -0
  41. data/lib/base_chip/problem.rb +33 -0
  42. data/lib/base_chip/project.rb +472 -0
  43. data/lib/base_chip/requirement.rb +26 -0
  44. data/lib/base_chip/runable.rb +36 -0
  45. data/lib/base_chip/source_language.rb +40 -0
  46. data/lib/base_chip/source_type.rb +24 -0
  47. data/lib/base_chip/statistic.rb +27 -0
  48. data/lib/base_chip/task.rb +21 -0
  49. data/lib/base_chip/task_master.rb +50 -0
  50. data/lib/base_chip/taskable.rb +77 -0
  51. data/lib/base_chip/tasker.rb +260 -0
  52. data/lib/base_chip/test.rb +202 -0
  53. data/lib/base_chip/test_list.rb +120 -0
  54. data/lib/base_chip/tool.rb +51 -0
  55. data/lib/base_chip/tool_version.rb +34 -0
  56. data/lib/base_chip/top_menu.rb +203 -0
  57. data/lib/base_chip/track_state.rb +61 -0
  58. data/lib/base_chip.rb +215 -0
  59. data/lib/dir.rb +30 -0
  60. data/lib/reporting.rb +97 -0
  61. metadata +215 -0
@@ -0,0 +1,50 @@
1
+ # Copyright 2011 Tommy Poulter
2
+ #
3
+ # This file is part of basechip.
4
+ #
5
+ # basechip is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 3 as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # basechip is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with basechip. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'yaml'
18
+ # require 'ipc'
19
+ YAML::ENGINE.yamler = 'psych'
20
+
21
+ module BaseChip
22
+ module TaskMaster
23
+ TASKER = Tasker
24
+ def self.included mod
25
+ mod.extend TaskMaster::ClassMethods
26
+ mod.class_eval do
27
+ include TaskMaster::InstanceMethods
28
+ attr_accessor :tasker
29
+ end
30
+ end
31
+ module ClassMethods
32
+ end
33
+ module InstanceMethods
34
+ def initialize(*args)
35
+ super(*args)
36
+ @tasker = TASKER.new
37
+ @tasker.task_master = self
38
+ end
39
+ def tasker_run_task
40
+ raise "Please extend tasker_run_task routine"
41
+ end
42
+ def tasker_handle_results(action, result)
43
+ raise "Please extend tasker_handle_results routine"
44
+ end
45
+ def tasker_empty
46
+ raise "Please extend tasker_run_task routine"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,77 @@
1
+ # Copyright 2011 Tommy Poulter
2
+ #
3
+ # This file is part of basechip.
4
+ #
5
+ # basechip is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 3 as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # basechip is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with basechip. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module BaseChip
18
+ module Taskable
19
+ def self.included mod
20
+ mod.extend Taskable::ClassMethods
21
+ mod.class_eval do
22
+ include Taskable::InstanceMethods
23
+ attr_accessor :task # for pointers to real tasks
24
+ attr_accessor :wait_count
25
+ attr_accessor :next_tasks
26
+ attr_accessor :task_name
27
+ attr_accessor :bundle_name
28
+ attr_accessor :bundle_tgz
29
+ attr_accessor :worker_command
30
+ attr_accessor :foreground
31
+ attr_accessor :totals
32
+ attr_accessor :state
33
+ end
34
+ end
35
+ module ClassMethods
36
+ end
37
+ module InstanceMethods
38
+
39
+ def initialize(*args)
40
+ super *args
41
+ initialize_taskable
42
+ end
43
+ def initialize_taskable
44
+ @wait_count = 0
45
+ @next_tasks = []
46
+ @totals = {}
47
+ end
48
+ def random_name
49
+ BaseChip.random_string
50
+ end
51
+
52
+ # nonportable but helpful to be here:
53
+ def deep_depends
54
+ # FIXME circular dependencies
55
+ return @deep_depends if @deep_depends
56
+ return @deep_depends = [] unless self.depends
57
+
58
+ @deep_depends = []
59
+ self.depends.each do |depend|
60
+ depend2 = depend.to_s.split(/:/)
61
+ while depend2.size < 3
62
+ depend2.unshift nil
63
+ end
64
+ depend2[0] ||= self.block .name.to_s
65
+ depend2[1] ||= self.configuration.name.to_s
66
+ @deep_depends += self.project.dereference_workload([depend2.join(':')])
67
+ end
68
+ @deep_depends.each do |d|
69
+ d.deep_configure
70
+ @deep_depends += d.deep_depends
71
+ end
72
+ @deep_depends.uniq!
73
+ @deep_depends
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,260 @@
1
+ # Copyright 2011 Tommy Poulter
2
+ #
3
+ # This file is part of basechip.
4
+ #
5
+ # basechip is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 3 as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # basechip is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with basechip. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'yaml'
18
+ # require 'ipc'
19
+ YAML::ENGINE.yamler = 'psych'
20
+
21
+ module BaseChip
22
+ class Tasker
23
+ include Ipc
24
+
25
+ CLEAR = "\e[0K"
26
+ attr_accessor :task_master
27
+
28
+ attr_accessor :foreground
29
+
30
+ attr_accessor :clusters
31
+
32
+ attr_accessor :workers
33
+
34
+ attr_accessor :pending_tasks
35
+ attr_accessor :running_tasks
36
+ attr_accessor :complete_tasks
37
+
38
+ attr_accessor :client_of
39
+ attr_accessor :client_id
40
+
41
+ def initialize(*args)
42
+ @workers = {}
43
+
44
+ @pending_tasks = []; @tasks_pending = 0
45
+ @running_tasks = []; @tasks_running = 0
46
+ @complete_tasks = []; @tasks_complete = 0
47
+ @tasks_passed = 0
48
+ @tasks_failed = 0
49
+
50
+ @mutex = Mutex.new
51
+
52
+ @server = self
53
+ end
54
+ def tasks_total
55
+ @tasks_pending + @tasks_running + @tasks_complete
56
+ end
57
+
58
+ def ready
59
+ init_test_sockets(:server)
60
+ end
61
+
62
+ def run
63
+ STDOUT.sync = true
64
+ if @client_of || @clusters.nil?
65
+ begin
66
+ if @client_of
67
+ init_test_sockets(:client)
68
+ end
69
+ while(t = @server.get_task(@client_id))
70
+ @task_master.tasker_run_task t
71
+ end
72
+ rescue DRb::DRbConnError
73
+ # raise if @options.debug
74
+ end
75
+ else
76
+ DRb.thread.join
77
+ end
78
+ end
79
+
80
+ def register_results(t, result, *additional)
81
+ if @client_of
82
+ @server.register_results(t, result, *additional)
83
+ return
84
+ end
85
+ @mutex.lock
86
+ inner_register_results(t, result, *additional)
87
+ @mutex.unlock
88
+ end
89
+ def inner_register_results(t, result, *additional)
90
+ return if @complete_tasks.select {|t2| t2.task_name == t.task_name}[0]
91
+ original_task = (@pending_tasks.select {|t2| t2.task_name == t.task_name}[0])
92
+ original_task ||= (@running_tasks.select {|t2| t2.task_name == t.task_name}[0])
93
+ raise "INTERNAL ERROR: couldn't find #{t.task_name}" unless original_task
94
+
95
+ if result == :cancel
96
+ @tasks_pending -= 1; @pending_tasks.delete original_task
97
+ else @tasks_running -= 1; @running_tasks.delete original_task
98
+ end
99
+ @complete_tasks << t
100
+ @tasks_complete += 1
101
+
102
+ if result == 'pass'
103
+ @tasks_passed += 1
104
+ original_task.next_tasks.each { |nt| nt.wait_count -= 1 }
105
+ else original_task.next_tasks.each { |nt| inner_register_results(nt,:cancel) }
106
+ @tasks_failed += 1 unless result == :cancel
107
+ end
108
+ @task_master.tasker_handle_results(t, result, *additional)
109
+ status_line
110
+
111
+ finish if (BaseChip.options.max_fails && @tasks_failed >= BaseChip.options.max_fails ) ||
112
+ (BaseChip.options.max_passes && @tasks_passed >= BaseChip.options.max_passes)
113
+ end
114
+ def status_line
115
+ return if @foreground
116
+ wr = workers_running
117
+ wa = workers_alive
118
+ wp = wa > 0 ? (100*wr/wa).round : 0
119
+ raise "Workload is empty" if tasks_total == 0
120
+ print "#{Tasker::CLEAR}complete:#{@tasks_complete}/#{tasks_total}(#{(100*@tasks_complete/tasks_total).round}%) workers:#{wr}/#{wa}(#{wp}%) pass:#{@tasks_passed} fail:#{@tasks_failed} run:#{@tasks_running} pend:#{@tasks_pending}\r"
121
+ end
122
+ def available_slots
123
+ count = 0
124
+ @clusters.each do |c|
125
+ count += c.available_slots
126
+ end
127
+ count
128
+ end
129
+ def spawn_worker(command)
130
+ @clusters.each do |c|
131
+ if c.available_slots > 0
132
+ c.slots_used += 1
133
+ return c, c.submit(command)
134
+ end
135
+ end
136
+ end
137
+ @@last_client_id = 0
138
+ def new_client_id
139
+ @@last_client_id += 1
140
+ end
141
+ def maintain_workers
142
+ ready = @pending_tasks.select {|t| t.wait_count == 0}
143
+ if @clusters
144
+ slots = available_slots
145
+ foo = ready.size - workers_spawned
146
+ foo = slots if slots < foo
147
+ if foo > 0
148
+ foo.times do |i|
149
+ client_id = new_client_id
150
+ cluster, uid = spawn_worker(ready[0].worker_command.call(client_id))
151
+ raise "spawn_worker response wasn't unique" if @workers[uid]
152
+ @workers[client_id] = {:uid => uid, :cluster=> cluster, :started=>Time.now, :tasks=>[], :state=>:spawned, :worker_command=>ready[i].worker_command.call(0)}
153
+ status_line
154
+ end
155
+ end
156
+ else
157
+ @workers[0] = {:started=>Time.now, :tasks=>[], :state=>:running, :worker_command=>ready[0].worker_command} if ready[0]
158
+ end
159
+
160
+ # puts "ready=#{(ready.*.task_name).inspect}"
161
+ ready
162
+ end
163
+
164
+ def submit_name(t_name,worker_command=nil)
165
+ task = Task.new
166
+ task.task_name = t_name
167
+ task.worker_command = worker_command if @clusters
168
+ submit(task)
169
+ end
170
+ def submit(task)
171
+ task.foreground = self.foreground
172
+ @pending_tasks << task
173
+ @tasks_pending += 1
174
+ maintain_workers
175
+ status_line
176
+ end
177
+ def submit_workload_chain(chain)
178
+ @pending_tasks = chain
179
+ @tasks_pending = chain.size
180
+ maintain_workers
181
+ status_line
182
+ end
183
+ def get_task(client_id)
184
+ @mutex.lock
185
+ ready = maintain_workers
186
+
187
+ w = @workers[client_id]
188
+ raise "Could not find worker based on unique id #{client_id}" unless w
189
+
190
+ t = nil
191
+ ready.each do |rt|
192
+ if rt.worker_command.nil? || rt.worker_command.call(0) == w[:worker_command]
193
+ t = rt
194
+ break
195
+ end
196
+ end
197
+
198
+ if t
199
+ @pending_tasks.delete t
200
+ @running_tasks << t
201
+ @tasks_pending -= 1
202
+ @tasks_running += 1
203
+
204
+ w[:tasks] << t
205
+ w[:state] = :running
206
+ else
207
+ w[:state] = :stopped
208
+ w[:cluster].slots_used -= 1 if w[:cluster]
209
+ end
210
+
211
+ finish if @pending_tasks.empty? && @running_tasks.empty? && ready.empty?
212
+
213
+ if @pending_tasks.size > 0 && @running_tasks.empty? && ready.empty?
214
+ raise("Could not build tasks because their dependencies never cleared: " + (@pending_tasks.map{|t|t.task_name}.join(" ")))
215
+ end
216
+
217
+ status_line
218
+ @mutex.unlock
219
+ t
220
+ end
221
+
222
+ def finish
223
+ return if @finishing
224
+ @finishing = true
225
+
226
+ kill
227
+ @task_master.tasker_finish
228
+ DRb.stop_service
229
+ end
230
+
231
+ def kill
232
+ locked = @mutex.try_lock
233
+ @workers.each do |id,w|
234
+ next if w[:stopped]
235
+ if w[:cluster] && (w[:state] != :stopped)
236
+ kill_message
237
+ w[:cluster].kill(w[:uid])
238
+ end
239
+ end
240
+ (@running_tasks + @pending_tasks).each do |t|
241
+ inner_register_results t, :cancel
242
+ end
243
+ @mutex.unlock if locked
244
+ end
245
+ def kill_message
246
+ return if @kill_message
247
+ @kill_message = true
248
+ puts "#{Tasker::CLEAR}\rClosing down all workers. Please be patient."
249
+ end
250
+
251
+ def workers_alive; c=0; @workers.each_value{|w| c+=1 if w[:state] != :stopped}; c end
252
+ def workers_running; c=0; @workers.each_value{|w| c+=1 if w[:state] == :running}; c end
253
+ def workers_spawned; c=0; @workers.each_value{|w| c+=1 if w[:state] == :spawned}; c end
254
+ def workers_stopped; c=0; @workers.each_value{|w| c+=1 if w[:state] == :stopped}; c end
255
+
256
+ def clear_line
257
+ print "#{Tasker::CLEAR}\r"
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,202 @@
1
+ # Copyright 2011 Tommy Poulter
2
+ #
3
+ # This file is part of basechip.
4
+ #
5
+ # basechip is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 3 as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # basechip is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with basechip. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'base_chip/action'
18
+
19
+ module BaseChip
20
+ class Test
21
+ include Taskable
22
+ include TrackState
23
+ include Runable
24
+ include Dsl
25
+ include Base
26
+ define_settings({:zip_failing_test => [ Boolean ],
27
+ :zip_passing_test => [ Boolean ],
28
+ :clean_passing_test => [ Boolean ],
29
+ :run_test_in_tmp => [ Boolean ],
30
+ :test_actions => [ Symbol , Array ]}.merge(Action.settings))
31
+ define_children(Action.child_types)
32
+
33
+ attr_accessor :original_actions
34
+ attr_accessor :action_extensions
35
+ # def actions
36
+ # parent.actions
37
+ # end
38
+
39
+ def configure
40
+ return if @configured
41
+ name_it
42
+ @directory ||= "#{parent.directory}/#{@name}"
43
+ super
44
+ end
45
+ def deep_configure
46
+ super
47
+
48
+ return if @deep_configured
49
+ @deep_configured = true
50
+
51
+ @test_actions = [@test_actions] unless @test_actions.is_a? Array
52
+ # @original_actions = @block.dereference_workload([@actions])[0]
53
+ fault "No test_actions exist for test list '#{@test_list}' to run in '#{@configuration.full_name}'" unless @configuration.actions
54
+ unless (@original_actions = @configuration.dereference_workload(@test_actions)) && @original_actions.size > 0
55
+ fault "Test list '#{@test_list.name}' in block:configuration '#{@block.name}:#{@configuration.name}' specified nonexistant action(s) '#{@test_actions}'. #{@test_list.file}"
56
+ end
57
+
58
+ @action_extensions = @original_actions.map do |a|
59
+ append_depends a.depends
60
+ a2 = a.clone
61
+ a2.clear
62
+ a2.parent = self # don't think I need to set foster here, because test list is a peer to action
63
+ a2.deep_configure
64
+ a2
65
+ end
66
+
67
+ @action_extensions.sort! do |a1,a2|
68
+ if a1.deep_depends.map{|d|d.name}.include? a2.name
69
+ 1
70
+ else
71
+ -1
72
+ end
73
+ end
74
+ end
75
+ # def find_parent_values
76
+ # super
77
+
78
+ # # @original_actions = @block.dereference_workload([@action])[0]
79
+ # @original_actions = @block.actions[@action]
80
+
81
+ # @original_actions. settings.each {|n,s| @children_settings[n] = s if s.value_set and not @children_settings[n].value_set }
82
+ # @original_actions.children_settings.each {|n,s| @children_settings[n] = s if s.value_set and not @children_settings[n].value_set }
83
+
84
+ # @action_extensions = Action.new
85
+ #
86
+ # # FIXME support outfile definition in Test
87
+ # @original_actions .out_files.each do |n,f|
88
+ # @action_extensions.out_files[n] = f.dup
89
+ # end
90
+
91
+ # @action_extensions.find_parent_values
92
+
93
+ # @action_extensions.name_it
94
+ # @name = @action_extensions.name
95
+ # end
96
+ # def find_parent_values
97
+ # super
98
+ # find_parent_values_of_underlying_action
99
+ # end
100
+
101
+ def name_it
102
+ if BaseChip.options.random_bundle_names
103
+ @name ||= random_name
104
+ elsif parent.autoname and not @name
105
+ if parent.autoname.respond_to? :each
106
+ parent.autoname.each do |an|
107
+ if md = /#{an}/.match(@args)
108
+ @name ||= (md[1] || md.to_s)
109
+ break
110
+ end
111
+ end
112
+ else
113
+ if md = /#{parent.autoname}/.match(@args)
114
+ @name ||= (md[1] || md.to_s)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ #def depends(dep=nil) ;(@action_extensions && @action_extensions.depends ) || super(dep) end
120
+ def bundle_name ; name end
121
+ def bundle_tgz ; "#{@directory}.tgz" end
122
+ def totals
123
+ return @totals if @totals
124
+ @totals = {}
125
+ @action_extensions.each do |a|
126
+ @totals.merge! a.totals
127
+ end
128
+ end
129
+ def run
130
+ if @run_test_in_tmp
131
+ bundle_name = random_string
132
+ run_directory = "/tmp/#{bundle_name}"
133
+ else
134
+ bundle_name = name
135
+ run_directory = @directory
136
+ end
137
+ FileUtils.rm_rf run_directory
138
+ FileUtils.mkdir_p run_directory
139
+ Dir.pushd run_directory
140
+
141
+ File.open('seed','w') do |f|
142
+ f.write random_generator.seed
143
+ end
144
+ File.open('rerun.yaml','w') do |f|
145
+ f.write rerun_data.to_yaml
146
+ end
147
+
148
+ @action_extensions.each do |a|
149
+ a.random_generator = Random.new(random_generator.rand(0x1_0000_0000))
150
+ a.foreground = @foreground
151
+ a.inner_run
152
+ take_state(a)
153
+ return unless pass?
154
+ end
155
+
156
+ Dir.chdir '..'
157
+ if (@clean_passing_test && pass? && !@foreground)
158
+ FileUtils.rm_rf run_directory
159
+ else
160
+ bundle_tgz = nil
161
+ if @zip_failing_test || (@zip_passing_test && pass?)
162
+ bundle_tgz = run_directory + ".tgz"
163
+ @bundle_tgz = @directory + ".tgz"
164
+ tgz = Zlib::GzipWriter.new(File.open(bundle_tgz, 'wb'))
165
+ Archive::Tar::Minitar.pack(bundle_name, tgz)
166
+ FileUtils.rm_rf bundle_name
167
+ end
168
+ if @run_test_in_tmp
169
+ FileUtils.mkdir_p "#{@directory}/../"
170
+ FileUtils.mv((bundle_tgz || run_directory), "#{@directory}/../")
171
+ end
172
+ end
173
+ Dir.popd
174
+
175
+ puts "Debug information here: #{@bundle_tgz || @directory}" if @foreground
176
+ end
177
+ # SAFE TO DELETE? def configuration_hash
178
+ # SAFE TO DELETE? super.merge @action_extensions.configuration_hash
179
+ # SAFE TO DELETE? end
180
+
181
+ def clean
182
+ end
183
+ def clobber
184
+ FileUtil.rm_rf directory
185
+ if Dir.empty? test_list.directory
186
+ FileUtil.rm_rf test_list.directory
187
+ end
188
+ end
189
+
190
+ # one random generator per test, all subordinate actions use it
191
+ def random_generator
192
+ @random_generator ||= BaseChip.new_random_generator
193
+ end
194
+
195
+ def rerun_data
196
+ { 'full_name' => full_name ,
197
+ 'seed' => random_generator.seed ,
198
+ 'append_arguments' => BaseChip.options. append_arguments ,
199
+ 'replace_arguments' => BaseChip.options.replace_arguments }
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,120 @@
1
+ # Copyright 2011 Tommy Poulter
2
+ #
3
+ # This file is part of basechip.
4
+ #
5
+ # basechip is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License version 3 as
7
+ # published by the Free Software Foundation.
8
+ #
9
+ # basechip is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with basechip. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'base_chip/test'
18
+ require 'base_chip/permute'
19
+ require 'base_chip/requirement'
20
+ require 'base_chip/post'
21
+ module BaseChip
22
+ class TestList
23
+ include Dsl
24
+ include Base
25
+ define_settings({:autoname => [ Regexp , Array ]})
26
+ define_children({:test => Test ,
27
+ :permute => Permute ,
28
+ :requirement => Requirement,
29
+ :post => Post })
30
+
31
+ def initialize
32
+ super
33
+ @num_tests = 0
34
+ end
35
+ # def actions
36
+ # parent.actions
37
+ # end
38
+ alias old_requirement requirement
39
+ alias old_post post
40
+ def requirement(name=:no_name,&blk); old_requirement(name,&blk) end
41
+ def post( name=:no_name,&blk); old_post( name,&blk) end
42
+ def configure
43
+ return if @configured
44
+ @directory ||= "#{configuration.out_directory}/#{name}"
45
+ super
46
+ return unless @tests
47
+ return unless @permutes
48
+ tests = @tests.values
49
+ @permutes.each_value do |permute|
50
+ permute.configure
51
+ next unless permute.permutations
52
+ tests.map! do |t|
53
+ permute.permutations.values.map do |permutation|
54
+ test = t.dup
55
+ test.name = "#{test.name}_#{permute.name}#{permutation.name}".to_sym
56
+ test.blks += permutation.blks
57
+ test
58
+ end
59
+ end
60
+ tests.flatten!
61
+ end
62
+
63
+ if @posts
64
+ tests.each do |t|
65
+ @posts.each_value do |p|
66
+ p.blks.each do |b|
67
+ b.call(t)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ if @requirements
73
+ new_tests = []
74
+ tests.each do |t|
75
+ t.configure
76
+ ditch = false
77
+ @requirements.each_value do |m|
78
+ m.blks.each do |b|
79
+ ditch = !(b.call t)
80
+ break if ditch
81
+ end
82
+ break if ditch
83
+ end
84
+ next if ditch
85
+ new_tests << t
86
+ end
87
+ tests = new_tests
88
+ end
89
+ @tests = {}
90
+ tests.each do |t|
91
+ name = t.name
92
+ i = 0
93
+ while @tests[name]
94
+ name = "#{t.name}_#{i+=1}"
95
+ end
96
+ t.name = name.to_sym
97
+ @tests[name] = t
98
+ end
99
+ end
100
+ def dereference_workload(tests = nil,passive = false)
101
+ configure
102
+ tests ||= ['all']
103
+ out = []
104
+ return out unless @tests
105
+ tests.each do |t|
106
+ if t == 'all'
107
+ out += @tests.values
108
+ else
109
+ if foo = @tests[t.to_sym]
110
+ out << foo
111
+ else
112
+ fault "Could not find test #{t.inspect} in list #{@name.inspect} in block #{@block.name.inspect}" unless passive
113
+ end
114
+ end
115
+ end
116
+ out
117
+ end
118
+
119
+ end
120
+ end