tldr 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Rakefile +1 -0
- data/lib/tldr/{parallelizer.rb → executor.rb} +9 -15
- data/lib/tldr/planner.rb +16 -4
- data/lib/tldr/reporters/default.rb +2 -2
- data/lib/tldr/runner.rb +35 -31
- data/lib/tldr/strategizer.rb +22 -7
- data/lib/tldr/value/plan.rb +1 -1
- data/lib/tldr/value/test.rb +3 -3
- data/lib/tldr/version.rb +1 -1
- data/lib/tldr.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e0c6abcfc7b58fc6de05591d61ceadfcbbed4867cfb140081f62877bb80d9a6
|
4
|
+
data.tar.gz: e62acff5d7e667214527d5bcafef6ba2540abbe4a187f441da07575919a34da0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c31d1f3fba81d133e2ef570b2252504cc67150d0729e56e0690fe5dbb8e3bd0512bec39e95a178eb12a8108fa92e56365fa981c3fc528ee3c845939237c347f
|
7
|
+
data.tar.gz: 3e35999424094dc072b6f2be670259e584dc14edf5621236a37efb0282c38c9ae434d63bd33fbe44b23f8fbf6f1b79fef801fb5f9375ff924d851c8063f63ba8
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## [0.6.1]
|
2
|
+
|
3
|
+
* Correctly report the number of test classes that run
|
4
|
+
* Finish planning the test run before starting the clock on the timer (that's
|
5
|
+
a millisecond or two in savings!)
|
6
|
+
|
1
7
|
## [0.6.0]
|
2
8
|
|
3
9
|
* When `dont_run_these_in_parallel!` and `run_these_together!` are called from a
|
data/Rakefile
CHANGED
@@ -1,26 +1,20 @@
|
|
1
1
|
class TLDR
|
2
|
-
class
|
2
|
+
class Executor
|
3
3
|
def initialize
|
4
|
-
@strategizer = Strategizer.new
|
5
4
|
@thread_pool = Concurrent::ThreadPoolExecutor.new(
|
6
5
|
name: "tldr",
|
7
6
|
auto_terminate: true
|
8
7
|
)
|
9
8
|
end
|
10
9
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
)
|
20
|
-
|
21
|
-
run_in_sequence(strategy.prepend_thread_unsafe_tests, &blk) +
|
22
|
-
run_in_parallel(strategy.parallel_tests_and_groups, &blk) +
|
23
|
-
run_in_sequence(strategy.thread_unsafe_tests, &blk)
|
10
|
+
def execute plan, &blk
|
11
|
+
if plan.strategy.parallel?
|
12
|
+
run_in_sequence(plan.strategy.prepend_sequential_tests, &blk) +
|
13
|
+
run_in_parallel(plan.strategy.parallel_tests_and_groups, &blk) +
|
14
|
+
run_in_sequence(plan.strategy.append_sequential_tests, &blk)
|
15
|
+
else
|
16
|
+
run_in_sequence(plan.tests, &blk)
|
17
|
+
end
|
24
18
|
end
|
25
19
|
|
26
20
|
private
|
data/lib/tldr/planner.rb
CHANGED
@@ -2,6 +2,10 @@ require "pathname"
|
|
2
2
|
|
3
3
|
class TLDR
|
4
4
|
class Planner
|
5
|
+
def initialize
|
6
|
+
@strategizer = Strategizer.new
|
7
|
+
end
|
8
|
+
|
5
9
|
def plan config
|
6
10
|
$VERBOSE = config.warnings
|
7
11
|
search_locations = PathUtil.expand_paths config.paths, globs: false
|
@@ -12,8 +16,7 @@ class TLDR
|
|
12
16
|
|
13
17
|
tests = gather_tests
|
14
18
|
config.update_after_gathering_tests! tests
|
15
|
-
|
16
|
-
Plan.new prepend(
|
19
|
+
tests_to_run = prepend(
|
17
20
|
shuffle(
|
18
21
|
exclude_by_path(
|
19
22
|
exclude_by_name(
|
@@ -29,6 +32,15 @@ class TLDR
|
|
29
32
|
),
|
30
33
|
config
|
31
34
|
)
|
35
|
+
|
36
|
+
strategy = @strategizer.strategize(
|
37
|
+
tests_to_run,
|
38
|
+
GROUPED_TESTS,
|
39
|
+
THREAD_UNSAFE_TESTS,
|
40
|
+
config
|
41
|
+
)
|
42
|
+
|
43
|
+
Plan.new tests_to_run, strategy
|
32
44
|
end
|
33
45
|
|
34
46
|
private
|
@@ -68,7 +80,7 @@ class TLDR
|
|
68
80
|
|
69
81
|
tests.reject { |test|
|
70
82
|
name_excludes.any? { |filter|
|
71
|
-
filter === test.
|
83
|
+
filter === test.method_name.to_s || filter === "#{test.test_class}##{test.method_name}"
|
72
84
|
}
|
73
85
|
}
|
74
86
|
end
|
@@ -89,7 +101,7 @@ class TLDR
|
|
89
101
|
|
90
102
|
tests.select { |test|
|
91
103
|
name_filters.any? { |filter|
|
92
|
-
filter === test.
|
104
|
+
filter === test.method_name.to_s || filter === "#{test.test_class}##{test.method_name}"
|
93
105
|
}
|
94
106
|
}
|
95
107
|
end
|
@@ -87,7 +87,7 @@ class TLDR
|
|
87
87
|
@out.print "Finished in #{duration}ms."
|
88
88
|
|
89
89
|
@out.print "\n\n"
|
90
|
-
class_count = test_results.uniq { |result| result.test.
|
90
|
+
class_count = test_results.uniq { |result| result.test.test_class }.size
|
91
91
|
test_count = test_results.size
|
92
92
|
@out.print [
|
93
93
|
plural(class_count, "test class", "test classes"),
|
@@ -127,7 +127,7 @@ class TLDR
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def describe test, location = test.location
|
130
|
-
"#{test.
|
130
|
+
"#{test.test_class}##{test.method_name} [#{location.locator}]"
|
131
131
|
end
|
132
132
|
|
133
133
|
def plural count, singular, plural = "#{singular}s"
|
data/lib/tldr/runner.rb
CHANGED
@@ -3,7 +3,7 @@ require "irb"
|
|
3
3
|
class TLDR
|
4
4
|
class Runner
|
5
5
|
def initialize
|
6
|
-
@
|
6
|
+
@executor = Executor.new
|
7
7
|
@wip = Concurrent::Array.new
|
8
8
|
@results = Concurrent::Array.new
|
9
9
|
@run_aborted = Concurrent::AtomicBoolean.new false
|
@@ -12,8 +12,8 @@ class TLDR
|
|
12
12
|
def run config, plan
|
13
13
|
@wip.clear
|
14
14
|
@results.clear
|
15
|
-
reporter = config.reporter.new
|
16
|
-
reporter.before_suite
|
15
|
+
reporter = config.reporter.new(config)
|
16
|
+
reporter.before_suite(plan.tests)
|
17
17
|
|
18
18
|
time_bomb = Thread.new {
|
19
19
|
explode = proc do
|
@@ -34,34 +34,8 @@ class TLDR
|
|
34
34
|
end
|
35
35
|
}
|
36
36
|
|
37
|
-
results = @
|
38
|
-
|
39
|
-
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
|
40
|
-
wip_test = WIPTest.new test, start_time
|
41
|
-
@wip << wip_test
|
42
|
-
runtime = time_it(start_time) do
|
43
|
-
instance = test.klass.new
|
44
|
-
instance.setup if instance.respond_to? :setup
|
45
|
-
if instance.respond_to? :around
|
46
|
-
did_run = false
|
47
|
-
instance.around {
|
48
|
-
did_run = true
|
49
|
-
instance.send(test.method)
|
50
|
-
}
|
51
|
-
raise Error, "#{test.klass}#around failed to yield or call the passed test block" unless did_run
|
52
|
-
else
|
53
|
-
instance.send(test.method)
|
54
|
-
end
|
55
|
-
instance.teardown if instance.respond_to? :teardown
|
56
|
-
rescue Skip, Failure, StandardError => e
|
57
|
-
end
|
58
|
-
TestResult.new(test, e, runtime).tap do |result|
|
59
|
-
next if @run_aborted.true?
|
60
|
-
@results << result
|
61
|
-
@wip.delete wip_test
|
62
|
-
reporter.after_test result
|
63
|
-
fail_fast reporter, plan, result if result.failing? && config.fail_fast
|
64
|
-
end
|
37
|
+
results = @executor.execute(plan) { |test|
|
38
|
+
run_test(test, config, plan, reporter)
|
65
39
|
}.tap do
|
66
40
|
time_bomb.kill
|
67
41
|
end
|
@@ -74,6 +48,36 @@ class TLDR
|
|
74
48
|
|
75
49
|
private
|
76
50
|
|
51
|
+
def run_test test, config, plan, reporter
|
52
|
+
e = nil
|
53
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
|
54
|
+
wip_test = WIPTest.new test, start_time
|
55
|
+
@wip << wip_test
|
56
|
+
runtime = time_it(start_time) do
|
57
|
+
instance = test.test_class.new
|
58
|
+
instance.setup if instance.respond_to? :setup
|
59
|
+
if instance.respond_to? :around
|
60
|
+
did_run = false
|
61
|
+
instance.around {
|
62
|
+
did_run = true
|
63
|
+
instance.send(test.method_name)
|
64
|
+
}
|
65
|
+
raise Error, "#{test.test_class}#around failed to yield or call the passed test block" unless did_run
|
66
|
+
else
|
67
|
+
instance.send(test.method_name)
|
68
|
+
end
|
69
|
+
instance.teardown if instance.respond_to? :teardown
|
70
|
+
rescue Skip, Failure, StandardError => e
|
71
|
+
end
|
72
|
+
TestResult.new(test, e, runtime).tap do |result|
|
73
|
+
next if @run_aborted.true?
|
74
|
+
@results << result
|
75
|
+
@wip.delete wip_test
|
76
|
+
reporter.after_test result
|
77
|
+
fail_fast reporter, plan, result if result.failing? && config.fail_fast
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
77
81
|
def fail_fast reporter, plan, fast_failed_result
|
78
82
|
unless @run_aborted.true?
|
79
83
|
@run_aborted.make_true
|
data/lib/tldr/strategizer.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
class TLDR
|
2
2
|
class Strategizer
|
3
|
-
Strategy = Struct.new :
|
3
|
+
Strategy = Struct.new :parallel?, :prepend_sequential_tests,
|
4
|
+
:parallel_tests_and_groups, :append_sequential_tests,
|
5
|
+
keyword_init: true
|
4
6
|
|
5
7
|
# Combine all discovered test methods with any methods grouped by run_these_together!
|
6
8
|
#
|
@@ -8,13 +10,15 @@ class TLDR
|
|
8
10
|
# - Map over tests to build out groups in order to retain shuffle order
|
9
11
|
# (group will run in position of first test in the group)
|
10
12
|
# - If a test is in multiple groups, only run it once
|
11
|
-
def strategize all_tests, run_these_together_groups, thread_unsafe_test_groups,
|
13
|
+
def strategize all_tests, run_these_together_groups, thread_unsafe_test_groups, config
|
14
|
+
return Strategy.new(parallel?: false) if run_sequentially?(all_tests, config)
|
15
|
+
|
12
16
|
thread_unsafe_tests, thread_safe_tests = partition_unsafe(all_tests, thread_unsafe_test_groups)
|
13
|
-
|
17
|
+
prepend_sequential_tests, append_sequential_tests = partition_prepend(thread_unsafe_tests, config)
|
14
18
|
|
15
|
-
grouped_tests = prepare_run_together_groups run_these_together_groups, thread_safe_tests,
|
19
|
+
grouped_tests = prepare_run_together_groups run_these_together_groups, thread_safe_tests, append_sequential_tests
|
16
20
|
already_included_groups = []
|
17
|
-
|
21
|
+
parallel_tests_and_groups = thread_safe_tests.map { |test|
|
18
22
|
if (group = grouped_tests.find { |group| group.tests.include? test })
|
19
23
|
if already_included_groups.include? group
|
20
24
|
next
|
@@ -28,11 +32,21 @@ class TLDR
|
|
28
32
|
else
|
29
33
|
test
|
30
34
|
end
|
31
|
-
}.compact
|
35
|
+
}.compact
|
36
|
+
Strategy.new(
|
37
|
+
parallel?: true,
|
38
|
+
prepend_sequential_tests:,
|
39
|
+
parallel_tests_and_groups:,
|
40
|
+
append_sequential_tests:
|
41
|
+
)
|
32
42
|
end
|
33
43
|
|
34
44
|
private
|
35
45
|
|
46
|
+
def run_sequentially? all_tests, config
|
47
|
+
all_tests.size < 2 || !config.parallel
|
48
|
+
end
|
49
|
+
|
36
50
|
def partition_unsafe tests, thread_unsafe_test_groups
|
37
51
|
tests.partition { |test|
|
38
52
|
thread_unsafe_test_groups.any? { |group| group.tests.include? test }
|
@@ -41,7 +55,8 @@ class TLDR
|
|
41
55
|
|
42
56
|
# Sadly duplicative with Planner.rb, necessitating the extraction of PathUtil
|
43
57
|
# Suboptimal, but we do indeed need to do this work in two places ¯\_(ツ)_/¯
|
44
|
-
def partition_prepend thread_unsafe_tests,
|
58
|
+
def partition_prepend thread_unsafe_tests, config
|
59
|
+
prepend_paths = config.no_prepend ? [] : config.prepend_paths
|
45
60
|
locations = PathUtil.expand_paths prepend_paths
|
46
61
|
|
47
62
|
thread_unsafe_tests.partition { |test|
|
data/lib/tldr/value/plan.rb
CHANGED
data/lib/tldr/value/test.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
class TLDR
|
2
|
-
Test = Struct.new :
|
2
|
+
Test = Struct.new :test_class, :method_name do
|
3
3
|
attr_reader :file, :line, :location
|
4
4
|
|
5
5
|
def initialize(*args)
|
6
6
|
super
|
7
|
-
@file, @line = SorbetCompatibility.unwrap_method(
|
7
|
+
@file, @line = SorbetCompatibility.unwrap_method(test_class.instance_method(method_name)).source_location
|
8
8
|
@location = Location.new file, line
|
9
9
|
end
|
10
10
|
|
11
11
|
# Memoizing at call time, because re-parsing isn't free and isn't usually necessary
|
12
12
|
def end_line
|
13
13
|
@end_line ||= begin
|
14
|
-
test_method = SorbetCompatibility.unwrap_method
|
14
|
+
test_method = SorbetCompatibility.unwrap_method test_class.instance_method(method_name)
|
15
15
|
RubyVM::AbstractSyntaxTree.of(test_method).last_lineno
|
16
16
|
end
|
17
17
|
end
|
data/lib/tldr/version.rb
CHANGED
data/lib/tldr.rb
CHANGED
@@ -5,8 +5,8 @@ require_relative "tldr/assertions"
|
|
5
5
|
require_relative "tldr/backtrace_filter"
|
6
6
|
require_relative "tldr/class_util"
|
7
7
|
require_relative "tldr/error"
|
8
|
+
require_relative "tldr/executor"
|
8
9
|
require_relative "tldr/parallel_controls"
|
9
|
-
require_relative "tldr/parallelizer"
|
10
10
|
require_relative "tldr/path_util"
|
11
11
|
require_relative "tldr/planner"
|
12
12
|
require_relative "tldr/reporters"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tldr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
@@ -61,8 +61,8 @@ files:
|
|
61
61
|
- lib/tldr/backtrace_filter.rb
|
62
62
|
- lib/tldr/class_util.rb
|
63
63
|
- lib/tldr/error.rb
|
64
|
+
- lib/tldr/executor.rb
|
64
65
|
- lib/tldr/parallel_controls.rb
|
65
|
-
- lib/tldr/parallelizer.rb
|
66
66
|
- lib/tldr/path_util.rb
|
67
67
|
- lib/tldr/planner.rb
|
68
68
|
- lib/tldr/rake.rb
|
@@ -107,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
107
|
- !ruby/object:Gem::Version
|
108
108
|
version: '0'
|
109
109
|
requirements: []
|
110
|
-
rubygems_version: 3.4.
|
110
|
+
rubygems_version: 3.4.17
|
111
111
|
signing_key:
|
112
112
|
specification_version: 4
|
113
113
|
summary: TLDR will run your tests, but only for 1.8 seconds.
|