delta_test 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +63 -14
- data/Rakefile +16 -3
- data/circle.yml +8 -1
- data/delta_test.gemspec +4 -3
- data/ext/delta_test/delta_test_native.c +154 -0
- data/ext/delta_test/delta_test_native.h +15 -0
- data/ext/delta_test/extconf.rb +12 -0
- data/lib/delta_test.rb +8 -2
- data/lib/delta_test/cli.rb +108 -21
- data/lib/delta_test/configuration.rb +91 -35
- data/lib/delta_test/dependencies_table.rb +15 -1
- data/lib/delta_test/generator.rb +42 -29
- data/lib/delta_test/profiler.rb +5 -0
- data/lib/delta_test/related_spec_list.rb +67 -8
- data/lib/delta_test/spec_helpers.rb +9 -7
- data/lib/delta_test/version.rb +1 -1
- data/spec/lib/delta_test/cli_spec.rb +26 -5
- data/spec/lib/delta_test/configuration_spec.rb +12 -0
- data/spec/lib/delta_test/dependencies_table_spec.rb +35 -0
- data/spec/lib/delta_test/generator_spec.rb +34 -17
- data/spec/lib/delta_test/profiler_spec.rb +121 -0
- data/spec/lib/delta_test/related_spec_list_spec.rb +150 -34
- data/spec/lib/delta_test/spec_helpers_spec.rb +11 -5
- data/spec/rails/Gemfile +8 -2
- data/spec/rails/Gemfile.lock +37 -3
- data/spec/rails/app/models/category.rb +14 -0
- data/spec/rails/app/models/comment.rb +20 -0
- data/spec/rails/app/models/post.rb +23 -0
- data/spec/rails/app/models/post_categorizing.rb +14 -0
- data/spec/rails/app/models/user.rb +15 -0
- data/spec/rails/db/migrate/20150518052022_create_users.rb +9 -0
- data/spec/rails/db/migrate/20150518052057_create_posts.rb +11 -0
- data/spec/rails/db/migrate/20150518052332_create_comments.rb +11 -0
- data/spec/rails/db/migrate/20150518052523_create_categories.rb +9 -0
- data/spec/rails/db/migrate/20150518052604_create_post_categorizings.rb +10 -0
- data/spec/rails/db/schema.rb +59 -0
- data/spec/rails/spec/factories/categories.rb +5 -0
- data/spec/rails/spec/factories/comments.rb +8 -0
- data/spec/rails/spec/factories/post_categorizings.rb +6 -0
- data/spec/rails/spec/factories/posts.rb +7 -0
- data/spec/rails/spec/factories/users.rb +5 -0
- data/spec/rails/spec/models/category_spec.rb +3 -0
- data/spec/rails/spec/models/comment_spec.rb +3 -0
- data/spec/rails/spec/models/post_categorizing_spec.rb +3 -0
- data/spec/rails/spec/models/post_spec.rb +3 -0
- data/spec/rails/spec/models/user_spec.rb +20 -0
- data/spec/rails/spec/spec_helper.rb +53 -9
- data/spec/spec_helper.rb +2 -0
- metadata +79 -19
- data/lib/delta_test/analyzer.rb +0 -47
- data/spec/lib/delta_test/analyzer_spec.rb +0 -126
data/lib/delta_test/cli.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'open3'
|
2
2
|
require 'shellwords'
|
3
|
+
require 'thread'
|
4
|
+
require 'thwait'
|
3
5
|
|
4
6
|
require_relative 'related_spec_list'
|
5
7
|
|
@@ -12,6 +14,10 @@ module DeltaTest
|
|
12
14
|
'verbose' => false,
|
13
15
|
}.freeze
|
14
16
|
|
17
|
+
BUNDLE_EXEC = ['bundle', 'exec'].freeze
|
18
|
+
|
19
|
+
SPLITTER = '--'
|
20
|
+
|
15
21
|
attr_reader *%i[
|
16
22
|
args
|
17
23
|
command
|
@@ -54,6 +60,8 @@ module DeltaTest
|
|
54
60
|
do_table
|
55
61
|
when 'exec'
|
56
62
|
do_exec
|
63
|
+
when 'clear'
|
64
|
+
do_clear
|
57
65
|
when '-v', '--version'
|
58
66
|
do_version
|
59
67
|
else
|
@@ -111,8 +119,8 @@ module DeltaTest
|
|
111
119
|
#
|
112
120
|
# @return {Boolean}
|
113
121
|
###
|
114
|
-
def
|
115
|
-
Git.same_commit?(@options['base'], @options['head'])
|
122
|
+
def profile_mode?
|
123
|
+
@profile_mode ||= Git.same_commit?(@options['base'], @options['head'])
|
116
124
|
end
|
117
125
|
|
118
126
|
###
|
@@ -148,24 +156,53 @@ module DeltaTest
|
|
148
156
|
spec_files = nil
|
149
157
|
args = []
|
150
158
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
159
|
+
begin
|
160
|
+
unless profile_mode?
|
161
|
+
@list.load_table!
|
162
|
+
@list.retrive_changed_files!(@options['base'], @options['head'])
|
163
|
+
|
164
|
+
spec_files = @list.related_spec_files.to_a
|
165
|
+
|
166
|
+
if spec_files.empty?
|
167
|
+
exit_with_message(0, 'Nothing to test')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
rescue TableNotFoundError
|
171
|
+
# force profile mode cuz we don't have a table
|
172
|
+
@profile_mode = true
|
173
|
+
end
|
158
174
|
|
159
|
-
|
160
|
-
@list.retrive_changed_files!(@options['base'], @options['head'])
|
175
|
+
@args.map! { |arg| Shellwords.escape(arg) }
|
161
176
|
|
162
|
-
|
177
|
+
if (splitter = @args.index(SPLITTER))
|
178
|
+
files = @args.drop(splitter + 1)
|
179
|
+
@args = @args.take(splitter)
|
163
180
|
|
164
|
-
if
|
165
|
-
|
181
|
+
if files && files.any?
|
182
|
+
if spec_files
|
183
|
+
pattern = files.map { |file| Regexp.escape(file) }
|
184
|
+
pattern = '^(%s)' % pattern.join('|')
|
185
|
+
spec_files = spec_files.grep(pattern)
|
186
|
+
else
|
187
|
+
spec_files = files
|
188
|
+
end
|
166
189
|
end
|
167
190
|
end
|
168
191
|
|
192
|
+
if profile_mode?
|
193
|
+
args << ('%s=%s' % [VERBOSE_FLAG, true]) if DeltaTest.verbose?
|
194
|
+
args << ('%s=%s' % [ACTIVE_FLAG, true])
|
195
|
+
end
|
196
|
+
|
197
|
+
if spec_files
|
198
|
+
args.unshift('cat', '|')
|
199
|
+
args << 'xargs'
|
200
|
+
end
|
201
|
+
|
202
|
+
if bundler_enabled? && BUNDLE_EXEC != @args.take(2)
|
203
|
+
args += BUNDLE_EXEC
|
204
|
+
end
|
205
|
+
|
169
206
|
args += @args
|
170
207
|
args = args.join(' ')
|
171
208
|
|
@@ -174,11 +211,32 @@ module DeltaTest
|
|
174
211
|
Open3.popen3(args) do |i, o, e, w|
|
175
212
|
i.write(spec_files.join("\n")) if spec_files
|
176
213
|
i.close
|
177
|
-
|
178
|
-
|
214
|
+
|
215
|
+
threads = []
|
216
|
+
threads << Thread.new { o.each { |l| puts l } }
|
217
|
+
threads << Thread.new { e.each { |l| $stderr.puts l } }
|
218
|
+
|
219
|
+
ThreadsWait.all_waits(*threads)
|
220
|
+
exit w.value.exitstatus
|
179
221
|
end
|
180
222
|
end
|
181
223
|
|
224
|
+
###
|
225
|
+
# Clean up tables and caches
|
226
|
+
###
|
227
|
+
def do_clear
|
228
|
+
table_file_path = DeltaTest.config.table_file_path('')
|
229
|
+
|
230
|
+
return unless table_file_path
|
231
|
+
|
232
|
+
args = [
|
233
|
+
'rm',
|
234
|
+
'%s*' % Shellwords.escape(table_file_path),
|
235
|
+
]
|
236
|
+
|
237
|
+
Open3.capture3(args.join(' ')) rescue nil
|
238
|
+
end
|
239
|
+
|
182
240
|
###
|
183
241
|
# Show version
|
184
242
|
###
|
@@ -194,9 +252,9 @@ module DeltaTest
|
|
194
252
|
puts "Command not found: #{@command}"
|
195
253
|
end
|
196
254
|
|
197
|
-
puts
|
255
|
+
puts <<HELP
|
198
256
|
usage: delta_test <command> [--base=<base>] [--head=<head>] [--verbose] [<args>]
|
199
|
-
[-v]
|
257
|
+
[-v|--version]
|
200
258
|
|
201
259
|
options:
|
202
260
|
--base=<base> A branch or a commit id to diff from.
|
@@ -215,9 +273,38 @@ commands:
|
|
215
273
|
|
216
274
|
table Show dependencies table.
|
217
275
|
|
218
|
-
exec <script>
|
219
|
-
|
220
|
-
|
276
|
+
exec <script> [-- <files>]
|
277
|
+
Execute test script using delta_test.
|
278
|
+
if <base> and <head> is the same commit or no dependencies table is found,
|
279
|
+
it'll run full test cases with a profile mode to create a table.
|
280
|
+
Otherwise, it'll run test script with only related spec files
|
281
|
+
passed by its arguments, like `delta_test list | xargs script'.
|
282
|
+
|
283
|
+
clear Clean up tables and caches.
|
284
|
+
HELP
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
private
|
289
|
+
|
290
|
+
###
|
291
|
+
# Check bundler existance
|
292
|
+
#
|
293
|
+
# @see http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
|
294
|
+
###
|
295
|
+
def bundler_enabled?
|
296
|
+
return true if Object.const_defined?(:Bundler)
|
297
|
+
|
298
|
+
previous = nil
|
299
|
+
current = File.expand_path(Dir.pwd)
|
300
|
+
|
301
|
+
until !File.directory?(current) || current == previous
|
302
|
+
filename = File.join(current, 'Gemfile')
|
303
|
+
return true if File.exist?(filename)
|
304
|
+
current, previous = File.expand_path('..', current), current
|
305
|
+
end
|
306
|
+
|
307
|
+
false
|
221
308
|
end
|
222
309
|
|
223
310
|
end
|
@@ -8,11 +8,46 @@ require_relative 'utils'
|
|
8
8
|
module DeltaTest
|
9
9
|
class Configuration
|
10
10
|
|
11
|
+
module Validator
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.include(InstanceMethods)
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
|
20
|
+
def _validators
|
21
|
+
@_validators ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate(attr, message, &block)
|
25
|
+
_validators << [attr, message, block]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
module InstanceMethods
|
31
|
+
|
32
|
+
def validate!
|
33
|
+
self.class._validators.each do |attr, message, block|
|
34
|
+
raise ValidationError.new(attr, message) unless self.instance_eval(&block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
include Validator
|
43
|
+
|
11
44
|
CONFIG_FILES = [
|
12
45
|
'delta_test.yml',
|
13
46
|
'delta_test.yaml',
|
14
47
|
].freeze
|
15
48
|
|
49
|
+
PART_FILE_EXT = '.part-%s'
|
50
|
+
|
16
51
|
attr_accessor *%i[
|
17
52
|
base_path
|
18
53
|
files
|
@@ -20,6 +55,7 @@ module DeltaTest
|
|
20
55
|
table_file
|
21
56
|
patterns
|
22
57
|
exclude_patterns
|
58
|
+
full_test_patterns
|
23
59
|
custom_mappings
|
24
60
|
]
|
25
61
|
|
@@ -29,14 +65,43 @@ module DeltaTest
|
|
29
65
|
table_file_path
|
30
66
|
]
|
31
67
|
|
68
|
+
validate :base_path, 'need to be an absolute path' do
|
69
|
+
self.base_path.absolute?
|
70
|
+
end
|
71
|
+
|
72
|
+
validate :files, 'need to be an array' do
|
73
|
+
self.files.is_a?(Array)
|
74
|
+
end
|
75
|
+
|
76
|
+
validate :patterns, 'need to be an array' do
|
77
|
+
self.patterns.is_a?(Array)
|
78
|
+
end
|
79
|
+
|
80
|
+
validate :exclude_patterns, 'need to be an array' do
|
81
|
+
self.exclude_patterns.is_a?(Array)
|
82
|
+
end
|
83
|
+
|
84
|
+
validate :full_test_patterns, 'need to be an array' do
|
85
|
+
self.full_test_patterns.is_a?(Array)
|
86
|
+
end
|
87
|
+
|
88
|
+
validate :custom_mappings, 'need to be a hash' do
|
89
|
+
self.custom_mappings.is_a?(Hash)
|
90
|
+
end
|
91
|
+
|
92
|
+
validate :custom_mappings, 'need to have an array in the contents' do
|
93
|
+
self.custom_mappings.values.all? { |v| v.is_a?(Array) }
|
94
|
+
end
|
95
|
+
|
32
96
|
def initialize
|
33
97
|
update do |c|
|
34
|
-
c.base_path
|
35
|
-
c.table_file
|
36
|
-
c.files
|
37
|
-
c.patterns
|
38
|
-
c.exclude_patterns
|
39
|
-
c.
|
98
|
+
c.base_path = File.expand_path('.')
|
99
|
+
c.table_file = 'tmp/.delta_test_dt'
|
100
|
+
c.files = []
|
101
|
+
c.patterns = []
|
102
|
+
c.exclude_patterns = []
|
103
|
+
c.full_test_patterns = []
|
104
|
+
c.custom_mappings = {}
|
40
105
|
end
|
41
106
|
end
|
42
107
|
|
@@ -64,6 +129,26 @@ module DeltaTest
|
|
64
129
|
end
|
65
130
|
|
66
131
|
|
132
|
+
# Override getters
|
133
|
+
#-----------------------------------------------
|
134
|
+
###
|
135
|
+
# Returns file path for the table
|
136
|
+
#
|
137
|
+
# @params {String} part
|
138
|
+
#
|
139
|
+
# @return {Pathname}
|
140
|
+
###
|
141
|
+
def table_file_path(part = nil)
|
142
|
+
return unless @table_file_path
|
143
|
+
|
144
|
+
if part
|
145
|
+
@table_file_path.sub_ext(PART_FILE_EXT % part)
|
146
|
+
else
|
147
|
+
@table_file_path
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
67
152
|
# Update
|
68
153
|
#-----------------------------------------------
|
69
154
|
###
|
@@ -77,35 +162,6 @@ module DeltaTest
|
|
77
162
|
precalculate!
|
78
163
|
end
|
79
164
|
|
80
|
-
###
|
81
|
-
# Validate option values
|
82
|
-
###
|
83
|
-
def validate!
|
84
|
-
if self.base_path.relative?
|
85
|
-
raise ValidationError.new(:base_path, 'need to be an absolute path')
|
86
|
-
end
|
87
|
-
|
88
|
-
unless self.files.is_a?(Array)
|
89
|
-
raise ValidationError.new(:files, 'need to be an array')
|
90
|
-
end
|
91
|
-
|
92
|
-
unless self.patterns.is_a?(Array)
|
93
|
-
raise ValidationError.new(:patterns, 'need to be an array')
|
94
|
-
end
|
95
|
-
|
96
|
-
unless self.exclude_patterns.is_a?(Array)
|
97
|
-
raise ValidationError.new(:exclude_patterns, 'need to be an array')
|
98
|
-
end
|
99
|
-
|
100
|
-
unless self.custom_mappings.is_a?(Hash)
|
101
|
-
raise ValidationError.new(:custom_mappings, 'need to be a hash')
|
102
|
-
|
103
|
-
unless self.custom_mappings.values.all? { |v| v.is_a?(Array) }
|
104
|
-
raise ValidationError.new(:custom_mappings, 'need to have an array in the contents')
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
165
|
###
|
110
166
|
# Precalculate some values
|
111
167
|
###
|
@@ -41,6 +41,21 @@ module DeltaTest
|
|
41
41
|
self[spec_file] << source_file if DeltaTest.config.filtered_files.include?(source_file)
|
42
42
|
end
|
43
43
|
|
44
|
+
###
|
45
|
+
# Reverse merge other table
|
46
|
+
#
|
47
|
+
# @params {DependenciesTable} other
|
48
|
+
###
|
49
|
+
def reverse_merge!(other)
|
50
|
+
raise TypeError unless other.is_a?(self.class)
|
51
|
+
|
52
|
+
other.each do |spec_file, source_files|
|
53
|
+
self[spec_file] |= source_files
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
44
59
|
###
|
45
60
|
# Temporary disable default_proc
|
46
61
|
# Because Marshal can't dump Hash with default_proc
|
@@ -70,7 +85,6 @@ module DeltaTest
|
|
70
85
|
# @params {String|Pathname} file
|
71
86
|
###
|
72
87
|
def dump(file)
|
73
|
-
# Marshal can't dump hash with default proc
|
74
88
|
without_default_proc do
|
75
89
|
cleanup!
|
76
90
|
data = Marshal.dump(self)
|
data/lib/delta_test/generator.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require_relative 'profiler'
|
2
4
|
require_relative 'dependencies_table'
|
3
5
|
|
4
6
|
require_relative 'utils'
|
@@ -12,11 +14,9 @@ module DeltaTest
|
|
12
14
|
]
|
13
15
|
|
14
16
|
###
|
15
|
-
# Setup
|
16
|
-
#
|
17
|
-
# @params {Boolean} _auto_teardown
|
17
|
+
# Setup table
|
18
18
|
###
|
19
|
-
def setup!
|
19
|
+
def setup!
|
20
20
|
return unless DeltaTest.active?
|
21
21
|
|
22
22
|
return if @_setup
|
@@ -24,16 +24,13 @@ module DeltaTest
|
|
24
24
|
|
25
25
|
DeltaTest.log('--- setup!')
|
26
26
|
|
27
|
-
@
|
28
|
-
@table = DependenciesTable.load(DeltaTest.config.table_file_path)
|
27
|
+
@table = DependenciesTable.load(DeltaTest.config.table_file_path)
|
29
28
|
|
30
29
|
@current_spec_file = nil
|
31
|
-
|
32
|
-
hook_on_exit { teardown! } if _auto_teardown
|
33
30
|
end
|
34
31
|
|
35
32
|
###
|
36
|
-
# Start
|
33
|
+
# Start profiler for the spec file
|
37
34
|
#
|
38
35
|
# @params {String} spec_file
|
39
36
|
###
|
@@ -43,27 +40,30 @@ module DeltaTest
|
|
43
40
|
DeltaTest.log('--- start!(%s)' % spec_file)
|
44
41
|
|
45
42
|
@current_spec_file = Utils.regulate_filepath(spec_file, DeltaTest.config.base_path).to_s
|
46
|
-
|
43
|
+
|
44
|
+
Profiler.start!
|
47
45
|
end
|
48
46
|
|
49
47
|
###
|
50
|
-
# Stop
|
48
|
+
# Stop profiler and update table
|
51
49
|
###
|
52
50
|
def stop!
|
53
51
|
return unless DeltaTest.active?
|
54
52
|
|
53
|
+
Profiler.stop!
|
54
|
+
|
55
55
|
DeltaTest.log('--- stop!')
|
56
56
|
|
57
57
|
spec_file = @current_spec_file
|
58
58
|
@current_spec_file = nil
|
59
59
|
|
60
|
-
@analyzer.stop
|
61
|
-
|
62
60
|
if spec_file
|
63
|
-
|
61
|
+
Profiler.last_result.each do |file|
|
64
62
|
@table.add(spec_file, file)
|
65
63
|
end
|
66
64
|
end
|
65
|
+
|
66
|
+
DeltaTest::Profiler.clean!
|
67
67
|
end
|
68
68
|
|
69
69
|
###
|
@@ -76,26 +76,39 @@ module DeltaTest
|
|
76
76
|
|
77
77
|
DeltaTest.log('--- teardown!')
|
78
78
|
|
79
|
-
|
80
|
-
@table.dump(DeltaTest.config.table_file_path)
|
81
|
-
end
|
79
|
+
Profiler.clean!
|
82
80
|
|
81
|
+
if defined?(ParallelTests)
|
82
|
+
if ParallelTests.first_process?
|
83
|
+
ParallelTests.wait_for_other_processes_to_finish
|
83
84
|
|
84
|
-
|
85
|
+
table_file_path = DeltaTest.config.table_file_path('*')
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
break unless ParallelTests.first_process?
|
93
|
-
ParallelTests.wait_for_other_processes_to_finish
|
94
|
-
end
|
87
|
+
Dir.glob(table_file_path).each do |part_file|
|
88
|
+
part_table = DependenciesTable.load(part_file)
|
89
|
+
@table.reverse_merge!(part_table)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
table_file_path = DeltaTest.config.table_file_path(ENV['TEST_ENV_NUMBER'])
|
95
93
|
|
96
|
-
|
94
|
+
@table.dump(table_file_path)
|
95
|
+
return
|
96
|
+
end
|
97
97
|
end
|
98
|
+
|
99
|
+
@table.dump(DeltaTest.config.table_file_path)
|
98
100
|
end
|
99
101
|
|
102
|
+
###
|
103
|
+
# Hook teardown! on exit
|
104
|
+
###
|
105
|
+
def hook_on_exit
|
106
|
+
at_exit { teardown! }
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
class GeneratorSingleton < Generator
|
112
|
+
include Singleton
|
100
113
|
end
|
101
114
|
end
|