delta_test 0.1.0 → 0.2.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.
- 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
|