realityforge-buildr 1.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE +176 -0
  4. data/NOTICE +26 -0
  5. data/README.md +3 -0
  6. data/Rakefile +50 -0
  7. data/addon/buildr/checkstyle-report.xsl +104 -0
  8. data/addon/buildr/checkstyle.rb +254 -0
  9. data/addon/buildr/git_auto_version.rb +36 -0
  10. data/addon/buildr/gpg.rb +90 -0
  11. data/addon/buildr/gwt.rb +413 -0
  12. data/addon/buildr/jacoco.rb +161 -0
  13. data/addon/buildr/pmd.rb +185 -0
  14. data/addon/buildr/single_intermediate_layout.rb +71 -0
  15. data/addon/buildr/spotbugs.rb +265 -0
  16. data/addon/buildr/top_level_generate_dir.rb +37 -0
  17. data/addon/buildr/wsgen.rb +192 -0
  18. data/bin/buildr +20 -0
  19. data/buildr.gemspec +61 -0
  20. data/lib/buildr.rb +86 -0
  21. data/lib/buildr/core/application.rb +705 -0
  22. data/lib/buildr/core/assets.rb +96 -0
  23. data/lib/buildr/core/build.rb +587 -0
  24. data/lib/buildr/core/common.rb +167 -0
  25. data/lib/buildr/core/compile.rb +599 -0
  26. data/lib/buildr/core/console.rb +124 -0
  27. data/lib/buildr/core/doc.rb +275 -0
  28. data/lib/buildr/core/environment.rb +128 -0
  29. data/lib/buildr/core/filter.rb +405 -0
  30. data/lib/buildr/core/help.rb +114 -0
  31. data/lib/buildr/core/progressbar.rb +161 -0
  32. data/lib/buildr/core/project.rb +994 -0
  33. data/lib/buildr/core/test.rb +776 -0
  34. data/lib/buildr/core/transports.rb +456 -0
  35. data/lib/buildr/core/util.rb +77 -0
  36. data/lib/buildr/ide/idea.rb +1664 -0
  37. data/lib/buildr/java/commands.rb +230 -0
  38. data/lib/buildr/java/compiler.rb +85 -0
  39. data/lib/buildr/java/custom_pom.rb +300 -0
  40. data/lib/buildr/java/doc.rb +62 -0
  41. data/lib/buildr/java/packaging.rb +393 -0
  42. data/lib/buildr/java/pom.rb +191 -0
  43. data/lib/buildr/java/test_result.rb +54 -0
  44. data/lib/buildr/java/tests.rb +111 -0
  45. data/lib/buildr/packaging/archive.rb +586 -0
  46. data/lib/buildr/packaging/artifact.rb +1113 -0
  47. data/lib/buildr/packaging/artifact_namespace.rb +1010 -0
  48. data/lib/buildr/packaging/artifact_search.rb +138 -0
  49. data/lib/buildr/packaging/package.rb +237 -0
  50. data/lib/buildr/packaging/version_requirement.rb +189 -0
  51. data/lib/buildr/packaging/zip.rb +189 -0
  52. data/lib/buildr/packaging/ziptask.rb +387 -0
  53. data/lib/buildr/version.rb +18 -0
  54. data/rakelib/release.rake +99 -0
  55. data/spec/addon/checkstyle_spec.rb +58 -0
  56. data/spec/core/application_spec.rb +576 -0
  57. data/spec/core/build_spec.rb +922 -0
  58. data/spec/core/common_spec.rb +670 -0
  59. data/spec/core/compile_spec.rb +656 -0
  60. data/spec/core/console_spec.rb +65 -0
  61. data/spec/core/doc_spec.rb +194 -0
  62. data/spec/core/extension_spec.rb +200 -0
  63. data/spec/core/project_spec.rb +736 -0
  64. data/spec/core/test_spec.rb +1131 -0
  65. data/spec/core/transport_spec.rb +452 -0
  66. data/spec/core/util_spec.rb +154 -0
  67. data/spec/ide/idea_spec.rb +1952 -0
  68. data/spec/java/commands_spec.rb +79 -0
  69. data/spec/java/compiler_spec.rb +274 -0
  70. data/spec/java/custom_pom_spec.rb +165 -0
  71. data/spec/java/doc_spec.rb +55 -0
  72. data/spec/java/packaging_spec.rb +786 -0
  73. data/spec/java/pom_spec.rb +162 -0
  74. data/spec/java/test_coverage_helper.rb +257 -0
  75. data/spec/java/tests_spec.rb +224 -0
  76. data/spec/packaging/archive_spec.rb +686 -0
  77. data/spec/packaging/artifact_namespace_spec.rb +757 -0
  78. data/spec/packaging/artifact_spec.rb +1351 -0
  79. data/spec/packaging/packaging_helper.rb +63 -0
  80. data/spec/packaging/packaging_spec.rb +690 -0
  81. data/spec/sandbox.rb +166 -0
  82. data/spec/spec_helpers.rb +420 -0
  83. data/spec/version_requirement_spec.rb +145 -0
  84. data/spec/xpath_matchers.rb +123 -0
  85. metadata +295 -0
@@ -0,0 +1,776 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+ module Buildr #:nodoc:
17
+
18
+ # The underlying test framework used by TestTask.
19
+ # To add a new test framework, extend TestFramework::Base and add your framework using:
20
+ # Buildr::TestFramework << MyFramework
21
+ module TestFramework
22
+
23
+ class << self
24
+
25
+ # Returns true if the specified test framework exists.
26
+ def has?(name)
27
+ frameworks.any? { |framework| framework.to_sym == name.to_sym }
28
+ end
29
+
30
+ # Select a test framework by its name.
31
+ def select(name)
32
+ frameworks.detect { |framework| framework.to_sym == name.to_sym }
33
+ end
34
+
35
+ # Identify which test framework applies for this project.
36
+ def select_from(project)
37
+ # Look for a suitable test framework based on the compiled language,
38
+ # which may return multiple candidates, e.g. JUnit and TestNG for Java.
39
+ # Pick the one used in the parent project, if not, whichever comes first.
40
+ candidates = frameworks.select { |framework| framework.applies_to?(project) }
41
+ parent = project.parent
42
+ parent && candidates.detect { |framework| framework.to_sym == parent.test.framework } || candidates.first
43
+ end
44
+
45
+ # Adds a test framework to the list of supported frameworks.
46
+ #
47
+ # For example:
48
+ # Buildr::TestFramework << Buildr::JUnit
49
+ def add(framework)
50
+ @frameworks ||= []
51
+ @frameworks |= [framework]
52
+ end
53
+ alias :<< :add
54
+
55
+ # Returns a list of available test frameworks.
56
+ def frameworks
57
+ @frameworks ||= []
58
+ end
59
+
60
+ end
61
+
62
+ # Base class for all test frameworks, with common functionality. Extend and over-ride as you see fit.
63
+ class Base
64
+
65
+ class << self
66
+
67
+ # The framework's identifier (e.g. :testng). Inferred from the class name.
68
+ def to_sym
69
+ @symbol ||= name.split('::').last.downcase.to_sym
70
+ end
71
+
72
+ # Returns true if this framework applies to the current project. For example, JUnit returns
73
+ # true if the tests are written in Java.
74
+ def applies_to?(project)
75
+ raise 'Not implemented'
76
+ end
77
+
78
+ # Returns a list of dependencies for this framework. Default is an empty list,
79
+ # override to add dependencies.
80
+ def dependencies
81
+ @dependencies ||= []
82
+ end
83
+ end
84
+
85
+ # Construct a new test framework with the specified options. Note that options may
86
+ # change before the framework is run.
87
+ def initialize(test_task, options)
88
+ @options = options
89
+ @task = test_task
90
+ end
91
+
92
+ # Options for this test framework.
93
+ attr_reader :options
94
+ # The test task we belong to
95
+ attr_reader :task
96
+
97
+ # Returns a list of dependenices for this framework. Defaults to calling the #dependencies
98
+ # method on the class.
99
+ def dependencies
100
+ self.class.dependencies
101
+ end
102
+
103
+ # TestTask calls this method to return a list of test names that can be run in this project.
104
+ # It then applies the include/exclude patterns to arrive at the list of tests that will be
105
+ # run, and call the #run method with that list.
106
+ #
107
+ # This method should return a list suitable for using with the #run method, but also suitable
108
+ # for the user to manage. For example, JUnit locates all the tests in the test.compile.target
109
+ # directory, and returns the class names, which are easier to work with than file names.
110
+ def tests(dependencies)
111
+ raise 'Not implemented'
112
+ end
113
+
114
+ # TestTask calls this method to run the named (and only those) tests. This method returns
115
+ # the list of tests that ran successfully.
116
+ def run(tests, dependencies)
117
+ raise 'Not implemented'
118
+ end
119
+ end
120
+ end
121
+
122
+
123
+ # The test task controls the entire test lifecycle.
124
+ #
125
+ # You can use the test task in three ways. You can access and configure specific test tasks,
126
+ # e.g. enhance the #compile task, or run code during #setup/#teardown.
127
+ #
128
+ # You can use convenient methods that handle the most common settings. For example,
129
+ # add dependencies using #with, or include only specific tests using #include.
130
+ #
131
+ # You can also enhance this task directly. This task will first execute the #compile task, followed
132
+ # by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown.
133
+ #
134
+ # The test framework is determined based on the available test files, for example, if the test
135
+ # cases are written in Java, then JUnit is selected as the test framework. You can also select
136
+ # a specific test framework, for example, to use TestNG instead of JUnit:
137
+ # test.using :testng
138
+ class TestTask < ::Rake::Task
139
+
140
+ class << self
141
+
142
+ # Used by the local test and integration tasks to
143
+ # a) Find the local project(s),
144
+ # b) Find all its sub-projects and narrow down to those that have either unit or integration tests,
145
+ # c) Run all the (either unit or integration) tests, and
146
+ # d) Ignore failure if necessary.
147
+ def run_local_tests(integration) #:nodoc:
148
+ Project.local_projects do |project|
149
+ # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^).
150
+ projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) }
151
+ projects.each do |project|
152
+ info "Testing #{project.name}"
153
+ # Invoke the prerequisites outside of the rescue block, otherwise errors converging
154
+ # the prerequisites are swallowed (and treated like failed test results). Moving the
155
+ # code outside means problems such as test code that does not compile will result in a
156
+ # build failure even if Buildr.options.test is set to :all
157
+ project.test.prerequisites.each{|p|p.is_a?(String) ? file(p).invoke : p.invoke}
158
+ begin
159
+ project.test.invoke
160
+ rescue
161
+ raise unless Buildr.options.test == :all
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ # Used by the test/integration rule to only run tests that match the specified names.
168
+ def only_run(tests) #:nodoc:
169
+ tests = wildcardify(tests)
170
+ # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
171
+ # all sub-projects, but only invoke test on the local project.
172
+ Project.projects.each { |project| project.test.send :only_run, tests }
173
+ end
174
+
175
+ # Used by the test/integration rule to only run tests that failed the last time.
176
+ def only_run_failed() #:nodoc:
177
+ # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
178
+ # all sub-projects, but only invoke test on the local project.
179
+ Project.projects.each { |project| project.test.send :only_run_failed }
180
+ end
181
+
182
+ # Used by the test/integration rule to clear all previously included/excluded tests.
183
+ def clear()
184
+ Project.projects.each do |project|
185
+ project.test.send :clear
186
+ end
187
+ end
188
+
189
+ # Used by the test/integration to include specific tests
190
+ def include(includes)
191
+ includes = wildcardify(Array(includes))
192
+ Project.projects.each do |project|
193
+ project.test.send :include, *includes if includes.size > 0
194
+ project.test.send :forced_need=, true
195
+ end
196
+ end
197
+
198
+ # Used by the test/integration to exclude specific tests
199
+ def exclude(excludes)
200
+ excludes = wildcardify(Array(excludes))
201
+ Project.projects.each do |project|
202
+ project.test.send :exclude, *excludes if excludes.size > 0
203
+ project.test.send :forced_need=, true
204
+ end
205
+ end
206
+
207
+ private
208
+
209
+ def wildcardify(strings)
210
+ strings.map { |name| name =~ /\*/ ? name : "*#{name}*" }
211
+ end
212
+ end
213
+
214
+ # Default options already set on each test task.
215
+ def default_options
216
+ { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} }
217
+ end
218
+
219
+ def initialize(*args) #:nodoc:
220
+ super
221
+ @dependencies = FileList[]
222
+ @include = []
223
+ @exclude = []
224
+ @forced_need = false
225
+ parent_task = Project.parent_task(name)
226
+ if parent_task.respond_to?(:options)
227
+ @options = OpenObject.new { |hash, key| hash[key] = parent_task.options[key].clone rescue hash[key] = parent_task.options[key] }
228
+ else
229
+ @options = OpenObject.new(default_options)
230
+ end
231
+
232
+ unless ENV["IGNORE_BUILDFILE"] =~ /(true)|(yes)/i
233
+ enhance [ application.buildfile.name ]
234
+ enhance application.buildfile.prerequisites
235
+ end
236
+ enhance do
237
+ run_tests if framework
238
+ end
239
+ end
240
+
241
+ # The dependencies used for running the tests. Includes the compiled files (compile.target)
242
+ # and their dependencies. Will also include anything you pass to #with, shared between the
243
+ # testing compile and run dependencies.
244
+ attr_accessor :dependencies
245
+
246
+ # *Deprecated*: Use dependencies instead.
247
+ def classpath
248
+ Buildr.application.deprecated 'Use dependencies instead.'
249
+ @dependencies
250
+ end
251
+
252
+ # *Deprecated*: Use dependencies= instead.
253
+ def classpath=(artifacts)
254
+ Buildr.application.deprecated 'Use dependencies= instead.'
255
+ @dependencies = artifacts
256
+ end
257
+
258
+ def execute(args) #:nodoc:
259
+ if Buildr.options.test == false
260
+ trace "Skipping tests for #{project.name}"
261
+ return
262
+ end
263
+ setup.invoke
264
+ begin
265
+ super
266
+ rescue RuntimeError
267
+ raise if options[:fail_on_failure] && Buildr.options.test != :all
268
+ ensure
269
+ teardown.invoke
270
+ end
271
+ end
272
+
273
+ # :call-seq:
274
+ # compile(*sources) => CompileTask
275
+ # compile(*sources) { |task| .. } => CompileTask
276
+ #
277
+ # The compile task is similar to the Project's compile task. However, it compiles all
278
+ # files found in the src/test/{source} directory into the target/test/{code} directory.
279
+ # This task is executed by the test task before running any tests.
280
+ #
281
+ # Once the project definition is complete, all dependencies from the regular
282
+ # compile task are copied over, so you only need to specify dependencies
283
+ # specific to your tests. You can do so by calling #with on the test task.
284
+ # The dependencies used here are also copied over to the junit task.
285
+ def compile(*sources, &block)
286
+ @project.task('test:compile').from(sources).enhance &block
287
+ end
288
+
289
+ # :call-seq:
290
+ # resources(*prereqs) => ResourcesTask
291
+ # resources(*prereqs) { |task| .. } => ResourcesTask
292
+ #
293
+ # Executes by the #compile task to copy resource files over. See Project#resources.
294
+ def resources(*prereqs, &block)
295
+ @project.task('test:resources').enhance prereqs, &block
296
+ end
297
+
298
+ # :call-seq:
299
+ # setup(*prereqs) => task
300
+ # setup(*prereqs) { |task| .. } => task
301
+ #
302
+ # Returns the setup task. The setup task is executed at the beginning of the test task,
303
+ # after compiling the test files.
304
+ def setup(*prereqs, &block)
305
+ @project.task('test:setup').enhance prereqs, &block
306
+ end
307
+
308
+ # :call-seq:
309
+ # teardown(*prereqs) => task
310
+ # teardown(*prereqs) { |task| .. } => task
311
+ #
312
+ # Returns the teardown task. The teardown task is executed at the end of the test task.
313
+ def teardown(*prereqs, &block)
314
+ @project.task('test:teardown').enhance prereqs, &block
315
+ end
316
+
317
+ # :call-seq:
318
+ # with(*specs) => self
319
+ #
320
+ # Specify artifacts (specs, tasks, files, etc) to include in the dependencies list
321
+ # when compiling and running tests.
322
+ def with(*artifacts)
323
+ @dependencies |= Buildr.artifacts(artifacts.flatten).uniq
324
+ compile.with artifacts
325
+ self
326
+ end
327
+
328
+ # Returns various test options.
329
+ attr_reader :options
330
+
331
+ # :call-seq:
332
+ # using(options) => self
333
+ #
334
+ # Sets various test options from a hash and returns self. For example:
335
+ # test.using :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' }
336
+ #
337
+ # Can also be used to select the test framework, or to run these tests as
338
+ # integration tests. For example:
339
+ # test.using :testng
340
+ # test.using :integration
341
+ #
342
+ # The :fail_on_failure option specifies whether the task should fail if
343
+ # any of the tests fail (default), or should report the failures but continue
344
+ # running the build (when set to false).
345
+ #
346
+ # All other options depend on the capability of the test framework. These options
347
+ # should be used the same way across all frameworks that support them:
348
+ # * :fork -- Fork once for each project (:once, default), for each test in each
349
+ # project (:each), or don't fork at all (false).
350
+ # * :properties -- Properties pass to the test, e.g. in Java as system properties.
351
+ # * :environment -- Environment variables. This hash is made available in the
352
+ # form of environment variables.
353
+ def using(*args)
354
+ args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last
355
+ args.each do |name|
356
+ if TestFramework.has?(name)
357
+ self.framework = name
358
+ elsif name == :integration
359
+ options[:integration] = true
360
+ end
361
+ end
362
+ self
363
+ end
364
+
365
+ # :call-seq:
366
+ # include(*names) => self
367
+ #
368
+ # Include only the specified tests. Unless specified, the default is to include
369
+ # all tests identified by the test framework. This method accepts multiple arguments
370
+ # and returns self.
371
+ #
372
+ # Tests are specified by their full name, but you can use glob patterns to select
373
+ # multiple tests, for example:
374
+ # test.include 'com.example.FirstTest' # FirstTest only
375
+ # test.include 'com.example.*' # All tests under com/example
376
+ # test.include 'com.example.Module*' # All tests starting with Module
377
+ # test.include '*.{First,Second}Test' # FirstTest, SecondTest
378
+ def include(*names)
379
+ @include += names
380
+ self
381
+ end
382
+
383
+ # :call-seq:
384
+ # exclude(*names) => self
385
+ #
386
+ # Exclude the specified tests. This method accepts multiple arguments and returns self.
387
+ # See #include for the type of arguments you can use.
388
+ def exclude(*names)
389
+ @exclude += names
390
+ self
391
+ end
392
+
393
+ # Clear all test includes and excludes and returns self
394
+ def clear
395
+ @include = []
396
+ @exclude = []
397
+ self
398
+ end
399
+
400
+ # *Deprecated*: Use tests instead.
401
+ def classes
402
+ Buildr.application.deprecated 'Call tests instead of classes'
403
+ tests
404
+ end
405
+
406
+ # After running the task, returns all tests selected to run, based on availability and include/exclude pattern.
407
+ attr_reader :tests
408
+ # After running the task, returns all the tests that failed, empty array if all tests passed.
409
+ attr_reader :failed_tests
410
+ # After running the task, returns all the tests that passed, empty array if no tests passed.
411
+ attr_reader :passed_tests
412
+
413
+ # :call-seq:
414
+ # framework => symbol
415
+ #
416
+ # Returns the test framework, e.g. :junit, :testng.
417
+ def framework
418
+ unless @framework
419
+ # Start with all frameworks that apply (e.g. JUnit and TestNG for Java),
420
+ # and pick the first (default) one, unless already specified in parent project.
421
+ candidates = TestFramework.frameworks.select { |cls| cls.applies_to?(@project) }
422
+ candidate = @project.parent && candidates.detect { |framework| framework.to_sym == @project.parent.test.framework } ||
423
+ candidates.first
424
+ self.framework = candidate if candidate
425
+ end
426
+ @framework && @framework.class.to_sym
427
+ end
428
+
429
+ # :call-seq:
430
+ # report_to => file
431
+ #
432
+ # Test frameworks that can produce reports, will write them to this directory.
433
+ #
434
+ # This is framework dependent, so unless you use the default test framework, call this method
435
+ # after setting the test framework.
436
+ def report_to
437
+ @report_to ||= file(@project.path_to(:reports, framework)=>self)
438
+ end
439
+
440
+ # :call-seq:
441
+ # failures_to => file
442
+ #
443
+ # We record the list of failed tests for the current framework in this file.
444
+ #
445
+ #
446
+ def failures_to
447
+ @failures_to ||= file(@project.path_to(:target, "#{framework}-failed")=>self)
448
+ end
449
+
450
+ # :call-seq:
451
+ # last_failures => array
452
+ #
453
+ # We read the last test failures if any and return them.
454
+ #
455
+ def last_failures
456
+ @last_failures ||= failures_to.exist? ? File.read(failures_to.to_s).split("\n") : []
457
+ end
458
+
459
+ # The path to the file that stores the time stamp of the last successful test run.
460
+ def last_successful_run_file #:nodoc:
461
+ File.join(report_to.to_s, 'last_successful_run')
462
+ end
463
+
464
+ # The time stamp of the last successful test run. Or Rake::EARLY if no successful test run recorded.
465
+ def timestamp #:nodoc:
466
+ File.exist?(last_successful_run_file) ? File.mtime(last_successful_run_file) : Rake::EARLY
467
+ end
468
+
469
+ # The project this task belongs to.
470
+ attr_reader :project
471
+
472
+ # Whether the tests are forced
473
+ attr_accessor :forced_need
474
+
475
+ protected
476
+
477
+ def associate_with(project)
478
+ @project = project
479
+ end
480
+
481
+ def framework=(name)
482
+ cls = TestFramework.select(name) or raise ArgumentError, "No #{name} test framework available. Did you install it?"
483
+ @framework = cls.new(self, options)
484
+ # Test framework dependency.
485
+ with @framework.dependencies
486
+ end
487
+
488
+ # :call-seq:
489
+ # include?(name) => boolean
490
+ #
491
+ # Returns true if the specified test name matches the inclusion/exclusion pattern. Used to determine
492
+ # which tests to execute.
493
+ def include?(name)
494
+ ((@include.empty? && !@forced_need)|| @include.any? { |pattern| File.fnmatch(pattern, name) }) &&
495
+ !@exclude.any? { |pattern| File.fnmatch(pattern, name) }
496
+ end
497
+
498
+ # Runs the tests using the selected test framework.
499
+ def run_tests
500
+ dependencies = (Buildr.artifacts(self.dependencies + compile.dependencies) + [compile.target]).map(&:to_s).uniq
501
+ rm_rf report_to.to_s
502
+ rm_rf failures_to.to_s
503
+ @tests = @framework.tests(dependencies).select { |test| include?(test) }.sort
504
+ if @tests.empty?
505
+ @passed_tests, @failed_tests = [], []
506
+ else
507
+ info "Running tests in #{@project.name}"
508
+ begin
509
+ # set the baseDir system property if not set
510
+ @framework.options[:properties] = { 'baseDir' => compile.target.to_s }.merge(@framework.options[:properties] || {})
511
+ @passed_tests = @framework.run(@tests, dependencies)
512
+ rescue Exception=>ex
513
+ error "Test framework error: #{ex.message}"
514
+ error ex.backtrace.join("\n") if trace?
515
+ @passed_tests = []
516
+ end
517
+ @failed_tests = @tests - @passed_tests
518
+ unless @failed_tests.empty?
519
+ Buildr::write(failures_to.to_s, @failed_tests.join("\n"))
520
+ error "The following tests failed:\n#{@failed_tests.join("\n")}"
521
+ fail 'Tests failed!'
522
+ end
523
+ end
524
+ record_successful_run unless @forced_need
525
+ end
526
+
527
+ # Call this method when a test run is successful to record the current system time.
528
+ def record_successful_run #:nodoc:
529
+ mkdir_p report_to.to_s
530
+ touch last_successful_run_file
531
+ end
532
+
533
+ # Limit running tests to specific list.
534
+ def only_run(tests)
535
+ @include = Array(tests)
536
+ @exclude.clear
537
+ @forced_need = true
538
+ end
539
+
540
+ # Limit running tests to those who failed the last time.
541
+ def only_run_failed()
542
+ @include = Array(last_failures)
543
+ @forced_need = true
544
+ end
545
+
546
+ def invoke_prerequisites(args, chain) #:nodoc:
547
+ @prerequisites |= FileList[@dependencies.uniq]
548
+ super
549
+ end
550
+
551
+ def needed? #:nodoc:
552
+ latest_prerequisite = @prerequisites.map { |p| application[p, @scope] }.max { |a,b| a.timestamp<=>b.timestamp }
553
+ needed = (timestamp == Rake::EARLY) || latest_prerequisite.timestamp > timestamp
554
+ trace "Testing#{needed ? ' ' : ' not '}needed. " +
555
+ "Latest prerequisite change: #{latest_prerequisite.timestamp} (#{latest_prerequisite.to_s}). " +
556
+ "Last successful test run: #{timestamp}."
557
+ return needed || @forced_need || Buildr.options.test == :all
558
+ end
559
+ end
560
+
561
+ # Methods added to Project to support compilation and running of tests.
562
+ module Test
563
+
564
+ include Extension
565
+
566
+ first_time do
567
+ desc 'Run all tests'
568
+ task('test') { TestTask.run_local_tests false }
569
+
570
+ desc 'Run failed tests'
571
+ task('test:failed') {
572
+ TestTask.only_run_failed
573
+ task('test').invoke
574
+ }
575
+
576
+ # This rule takes a suffix and runs that tests in the current project. For example;
577
+ # buildr test:MyTest
578
+ # will run the test com.example.MyTest, if such a test exists for this project.
579
+ #
580
+ # If you want to run multiple test, separate them with a comma. You can also use glob
581
+ # (* and ?) patterns to match multiple tests, see the TestTask#include method.
582
+ rule /^test:.*$/ do |task|
583
+ # The map works around a JRuby bug whereby the string looks fine, but fails in fnmatch.
584
+ tests = task.name.scan(/test:(.*)/)[0][0].split(',').map(&:to_s)
585
+ excludes, includes = tests.partition { |t| t =~ /^-/ }
586
+ if excludes.empty?
587
+ TestTask.only_run includes
588
+ else
589
+ # remove leading '-'
590
+ excludes.map! { |t| t[1..-1] }
591
+
592
+ TestTask.clear
593
+ TestTask.include(includes.empty? ? ['*'] : includes)
594
+ TestTask.exclude excludes
595
+ end
596
+ task('test').invoke
597
+ end
598
+
599
+ end
600
+
601
+ before_define(:test) do |project|
602
+ # Define a recursive test task, and pass it a reference to the project so it can discover all other tasks.
603
+ test = TestTask.define_task('test')
604
+ test.send :associate_with, project
605
+
606
+ # Similar to the regular resources task but using different paths.
607
+ resources = ResourcesTask.define_task('test:resources')
608
+ resources.send :associate_with, project, :test
609
+ project.path_to(:source, :test, :resources).tap { |dir| resources.from dir if File.exist?(dir) }
610
+
611
+ # We define a module inline that will inject cancelling the task if tests are skipped.
612
+ module SkipIfNoTest
613
+
614
+ def self.extended(base)
615
+ base.instance_eval {alias :execute_before_skip_if_no_test :execute}
616
+ base.instance_eval {alias :execute :execute_after_skip_if_no_test}
617
+ end
618
+
619
+ def execute_after_skip_if_no_test(args) #:nodoc:
620
+ if Buildr.options.test == false
621
+ trace "Skipping #{to_s} for #{project.name} as tests are skipped"
622
+ return
623
+ end
624
+ execute_before_skip_if_no_test(args)
625
+ end
626
+ end
627
+
628
+ # Similar to the regular compile task but using different paths.
629
+ compile = CompileTask.define_task('test:compile'=>[project.compile, resources])
630
+ compile.extend SkipIfNoTest
631
+ compile.send :associate_with, project, :test
632
+ test.enhance [compile]
633
+
634
+ # Define these tasks once, otherwise we may get a namespace error.
635
+ test.setup ; test.teardown
636
+ end
637
+
638
+
639
+
640
+ after_define(:test => :compile) do |project|
641
+ test = project.test
642
+ # Dependency on compiled tests and resources. Dependencies added using with.
643
+ test.dependencies.concat [test.compile.target, test.resources.target].compact
644
+ test.dependencies.concat test.compile.dependencies
645
+ # Dependency on compiled code, its dependencies and resources.
646
+ test.with [project.compile.target, project.resources.target].compact
647
+ test.with project.compile.dependencies
648
+ # Picking up the test frameworks adds further dependencies.
649
+ test.framework
650
+
651
+ project.build test unless test.options[:integration] || Buildr.options.test == :only
652
+
653
+ project.clean do
654
+ rm_rf test.compile.target.to_s if test.compile.target
655
+ rm_rf test.report_to.to_s
656
+ end
657
+ end
658
+
659
+
660
+ # :call-seq:
661
+ # test(*prereqs) => TestTask
662
+ # test(*prereqs) { |task| .. } => TestTask
663
+ #
664
+ # Returns the test task. The test task controls the entire test lifecycle.
665
+ #
666
+ # You can use the test task in three ways. You can access and configure specific
667
+ # test tasks, e.g. enhance the compile task by calling test.compile, setup for
668
+ # the tests by enhancing test.setup and so forth.
669
+ #
670
+ # You can use convenient methods that handle the most common settings. For example,
671
+ # add dependencies using test.with, or include only specific tests using test.include.
672
+ #
673
+ # You can also enhance this task directly. This method accepts a list of arguments
674
+ # that are used as prerequisites and an optional block that will be executed by the
675
+ # test task.
676
+ #
677
+ # This task compiles the project and the tests (in that order) before running any tests.
678
+ # It execute the setup task, runs all the tests, any enhancements, and ends with the
679
+ # teardown tasks.
680
+ def test(*prereqs, &block)
681
+ task('test').enhance prereqs, &block
682
+ end
683
+
684
+ # :call-seq:
685
+ # integration { |task| .... }
686
+ # integration => IntegrationTestTask
687
+ #
688
+ # Use this method to return the integration tests task, or enhance it with a block to execute.
689
+ #
690
+ # There is one integration tests task you can execute directly, or as a result of running the package
691
+ # task (or tasks that depend on it, like install and upload). It contains all the tests marked with
692
+ # :integration=>true, all other tests are considered unit tests and run by the test task before packaging.
693
+ # So essentially: build=>test=>packaging=>integration=>install/upload.
694
+ #
695
+ # You add new tests from projects that define integration tests using the regular test task,
696
+ # but with the following addition:
697
+ # test.using :integration
698
+ #
699
+ # Use this method to enhance the setup and teardown tasks that are executed before (and after) all
700
+ # integration tests are run, for example, to start a Web server or create a database.
701
+ def integration(*deps, &block)
702
+ Rake::Task['rake:integration'].enhance deps, &block
703
+ end
704
+
705
+ end
706
+
707
+
708
+ # :call-seq:
709
+ # integration { |task| .... }
710
+ # integration => IntegrationTestTask
711
+ #
712
+ # Use this method to return the integration tests task.
713
+ def integration(*deps, &block)
714
+ Rake::Task['rake:integration'].enhance deps, &block
715
+ end
716
+
717
+ class Options
718
+
719
+ # Runs tests after the build when true (default). This forces tests to execute
720
+ # after the build, including when running build related tasks like install, upload and release.
721
+ #
722
+ # Set to false to not run any tests. Set to :all to run all tests, ignoring failures.
723
+ #
724
+ # This option is set from the environment variable 'test', so you can also do:
725
+
726
+ # Returns the test option (environment variable TEST). Possible values are:
727
+ # * :false -- Do not run any tests (also accepts 'no' and 'skip').
728
+ # * :true -- Run all tests, stop on failure (default if not set).
729
+ # * :all -- Run all tests, ignore failures.
730
+ def test
731
+ case value = ENV['TEST'] || ENV['test']
732
+ when /^(no|off|false|skip)$/i
733
+ false
734
+ when /^all$/i
735
+ :all
736
+ when /^only$/i
737
+ :only
738
+ when /^(yes|on|true)$/i, nil
739
+ true
740
+ else
741
+ warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the tests and stop at failure."
742
+ true
743
+ end
744
+ end
745
+
746
+ # Sets the test option (environment variable TEST). Possible values are true, false or :all.
747
+ #
748
+ # You can also set this from the environment variable, e.g.:
749
+ #
750
+ # buildr # With tests
751
+ # buildr test=no # Without tests
752
+ # buildr test=all # Ignore failures
753
+ # set TEST=no
754
+ # buildr # Without tests
755
+ def test=(flag)
756
+ ENV['test'] = nil
757
+ ENV['TEST'] = flag.to_s
758
+ end
759
+
760
+ end
761
+
762
+ Buildr.help << <<-HELP
763
+ To run a full build without running any tests:
764
+ buildr test=no
765
+ To run specific test:
766
+ buildr test:MyTest
767
+ To run integration tests:
768
+ buildr integration
769
+ HELP
770
+
771
+ end
772
+
773
+
774
+ class Buildr::Project
775
+ include Buildr::Test
776
+ end