knapsack 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf3e5a9aba000c4d624a76850d39373731918bbdcba5c1627a98131983823ff9
4
- data.tar.gz: 524c4e365f94683bd571fbd33538aa737df1a4c44a73d66ee64d512097221c84
3
+ metadata.gz: d27f3b6225aefe7c7a2ff1a4071961e65c5e087a5256d7294bca73398ce2c997
4
+ data.tar.gz: 38f324e2d35800297e8c071caef06100688d1e1617bb8f3339076b9c9c1de828
5
5
  SHA512:
6
- metadata.gz: 0a365bc8c5bc58458191e864263184307d2a8c5fb3ecfba965c22e8f78d9a322af4a14b8721456ace7729e4a50c4df2f4788acb84141910202ebf9d6794b7bf9
7
- data.tar.gz: 82228079c42fb2c423f6085b402c7e014d99f96388b42d0d831e1e03d631bbe56980f9902eb498306a21cb67ae183dceeba43f82e94bc66c4397870ac68aa1bd
6
+ metadata.gz: 0d635a77401b2d65914edab41f2ac726901d38b937869fb408cc2548d6547114a0d968c06a8c9adfe4f5a2c3d3d7c11bea5bb0c8161d706e17870ea3682b5be0
7
+ data.tar.gz: b5aa3601e1d7cbdffdfa33a4de64d562782c74371f9e3c58b0754b262a86554c8320e7fb0aff1c84cd6e05755b66c29b61b87f83ffb3a44d4f06eb9c38c8dfd6
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  * TODO
4
4
 
5
+ ### 3.1.0
6
+
7
+ * Sorting Algorithm: round robin to least connections
8
+
9
+ https://github.com/KnapsackPro/knapsack/pull/99
10
+
11
+ https://github.com/KnapsackPro/knapsack/compare/v3.0.0...v3.1.0
12
+
5
13
  ### 3.0.0
6
14
 
7
15
  * __(breaking change)__ Require minimum Ruby 2.2 version
@@ -2,7 +2,7 @@ module Knapsack
2
2
  module Distributors
3
3
  class ReportDistributor < BaseDistributor
4
4
  def sorted_report
5
- @sorted_report ||= report.sort_by { |test_path, time| time }.reverse
5
+ @sorted_report ||= report.sort_by { |_test_path, time| -time }
6
6
  end
7
7
 
8
8
  def sorted_report_with_existing_tests
@@ -10,7 +10,7 @@ module Knapsack
10
10
  end
11
11
 
12
12
  def total_time_execution
13
- @total_time_execution ||= sorted_report_with_existing_tests.map(&:last).reduce(0, :+).to_f
13
+ @total_time_execution ||= sorted_report_with_existing_tests.map { |_test_path, time| time }.reduce(0, :+).to_f
14
14
  end
15
15
 
16
16
  def node_time_execution
@@ -20,73 +20,52 @@ module Knapsack
20
20
  private
21
21
 
22
22
  def post_assign_test_files_to_node
23
- assign_slow_test_files
24
- assign_remaining_test_files
23
+ assign_test_files
25
24
  sort_assigned_test_files
26
25
  end
27
26
 
28
27
  def sort_assigned_test_files
29
- ci_node_total.times do |index|
30
- # sort by first key (file name)
31
- # reverse it and then sort by second key (time) in reverse order
32
- node_tests[index][:test_files_with_time].sort!.reverse!.sort! do |x, y|
33
- y[1] <=> x[1]
34
- end
28
+ node_tests.map do |node|
29
+ node[:test_files_with_time]
30
+ .sort_by! { |file_name, _time| file_name }
31
+ .reverse!
32
+ .sort_by! { |_file_name, time| time }
33
+ .reverse!
35
34
  end
36
35
  end
37
36
 
38
37
  def post_tests_for_node(node_index)
39
38
  node_test = node_tests[node_index]
40
39
  return unless node_test
41
- node_test[:test_files_with_time].map(&:first)
40
+ node_test[:test_files_with_time].map { |file_name, _time| file_name }
42
41
  end
43
42
 
44
43
  def default_node_tests
45
- @node_tests = []
46
- ci_node_total.times do |index|
47
- @node_tests << {
44
+ @node_tests = Array.new(ci_node_total) do |index|
45
+ {
48
46
  node_index: index,
49
47
  time_left: node_time_execution,
50
- test_files_with_time: []
48
+ test_files_with_time: [],
49
+ weight: 0
51
50
  }
52
51
  end
53
52
  end
54
53
 
55
- def assign_slow_test_files
56
- @not_assigned_test_files = []
57
- node_index = 0
58
- sorted_report_with_existing_tests.each do |test_file_with_time|
59
- assign_slow_test_file(node_index, test_file_with_time)
60
- node_index += 1
61
- node_index %= ci_node_total
62
- end
63
- end
54
+ def assign_test_files
55
+ sorted_report_with_existing_tests.map do |test_file_with_time|
56
+ test_execution_time = test_file_with_time.last
64
57
 
65
- def assign_slow_test_file(node_index, test_file_with_time)
66
- time = test_file_with_time[1]
67
- time_left = node_tests[node_index][:time_left] - time
58
+ current_lightest_node = node_tests.min_by { |node| node[:weight] }
68
59
 
69
- if time_left >= 0 or node_tests[node_index][:test_files_with_time].empty?
70
- node_tests[node_index][:time_left] -= time
71
- node_tests[node_index][:test_files_with_time] << test_file_with_time
72
- else
73
- @not_assigned_test_files << test_file_with_time
74
- end
75
- end
60
+ updated_node_data = {
61
+ time_left: current_lightest_node[:time_left] - test_execution_time,
62
+ weight: current_lightest_node[:weight] + test_execution_time,
63
+ test_files_with_time: current_lightest_node[:test_files_with_time] << test_file_with_time
64
+ }
76
65
 
77
- def assign_remaining_test_files
78
- @not_assigned_test_files.each do |test_file_with_time|
79
- index = node_with_max_time_left
80
- time = test_file_with_time[1]
81
- node_tests[index][:time_left] -= time
82
- node_tests[index][:test_files_with_time] << test_file_with_time
66
+ current_lightest_node.merge!(updated_node_data)
83
67
  end
84
68
  end
85
-
86
- def node_with_max_time_left
87
- node_test = node_tests.max { |a,b| a[:time_left] <=> b[:time_left] }
88
- node_test[:node_index]
89
- end
90
69
  end
91
70
  end
92
71
  end
@@ -1,3 +1,3 @@
1
1
  module Knapsack
2
- VERSION = '3.0.0'
2
+ VERSION = '3.1.0'
3
3
  end
@@ -118,7 +118,7 @@ describe Knapsack::Distributors::ReportDistributor do
118
118
  'c_spec.rb' => 2.0,
119
119
  'd_spec.rb' => 2.5,
120
120
  'a_spec.rb' => 1.0,
121
- 'b_spec.rb' => 1.5,
121
+ 'b_spec.rb' => 1.5
122
122
  }
123
123
  end
124
124
  let(:custom_args) { { ci_node_total: 3 } }
@@ -134,6 +134,7 @@ describe Knapsack::Distributors::ReportDistributor do
134
134
  expect(distributor.node_tests[0]).to eql({
135
135
  :node_index => 0,
136
136
  :time_left => -0.5,
137
+ :weight => 9.0,
137
138
  :test_files_with_time => [
138
139
  ["g_spec.rb", 9.0]
139
140
  ]
@@ -143,12 +144,12 @@ describe Knapsack::Distributors::ReportDistributor do
143
144
  it do
144
145
  expect(distributor.node_tests[1]).to eql({
145
146
  :node_index => 1,
146
- :time_left => 0.0,
147
+ :time_left => 0.5,
148
+ :weight => 8.0,
147
149
  :test_files_with_time => [
148
150
  ["f_spec.rb", 3.5],
149
151
  ["d_spec.rb", 2.5],
150
- ["b_spec.rb", 1.5],
151
- ["a_spec.rb", 1.0]
152
+ ["c_spec.rb", 2.0]
152
153
  ]
153
154
  })
154
155
  end
@@ -156,11 +157,13 @@ describe Knapsack::Distributors::ReportDistributor do
156
157
  it do
157
158
  expect(distributor.node_tests[2]).to eql({
158
159
  :node_index => 2,
159
- :time_left => 0.5,
160
+ :time_left => 0.0,
161
+ :weight => 8.5,
160
162
  :test_files_with_time => [
161
- ["i_spec.rb", 3.0],
162
163
  ["h_spec.rb", 3.0],
163
- ["c_spec.rb", 2.0]
164
+ ["i_spec.rb", 3.0],
165
+ ["b_spec.rb", 1.5],
166
+ ["a_spec.rb", 1.0]
164
167
  ]
165
168
  })
166
169
  end
@@ -170,10 +173,9 @@ describe Knapsack::Distributors::ReportDistributor do
170
173
  context 'when node exists' do
171
174
  it do
172
175
  expect(distributor.tests_for_node(1)).to eql([
173
- 'f_spec.rb',
174
- 'd_spec.rb',
175
- 'b_spec.rb',
176
- 'a_spec.rb'
176
+ "f_spec.rb",
177
+ "d_spec.rb",
178
+ "c_spec.rb"
177
179
  ])
178
180
  end
179
181
  end
@@ -183,4 +185,78 @@ describe Knapsack::Distributors::ReportDistributor do
183
185
  end
184
186
  end
185
187
  end
188
+
189
+ describe 'algorithmic efficiency' do
190
+ subject(:node_weights) do
191
+ distro = distributor
192
+ distro.assign_test_files_to_node
193
+ distro.node_tests.map { |node| node[:weight] }
194
+ end
195
+
196
+ before do
197
+ allow(distributor).to receive(:all_tests).and_return(report.keys)
198
+ end
199
+
200
+ let(:custom_args) { { ci_node_total: 3 } }
201
+
202
+ context 'with the most simple example' do
203
+ let(:report) do
204
+ {
205
+ 'a_spec.rb' => 1.0,
206
+ 'b_spec.rb' => 1.0,
207
+ 'c_spec.rb' => 1.0,
208
+ 'd_spec.rb' => 1.0,
209
+ 'e_spec.rb' => 1.0,
210
+ 'f_spec.rb' => 1.0,
211
+ 'g_spec.rb' => 1.0,
212
+ 'h_spec.rb' => 1.0,
213
+ 'i_spec.rb' => 1.0
214
+ }
215
+ end
216
+
217
+ it 'assigns all nodes equally' do
218
+ expect(node_weights.uniq).to contain_exactly 3.0
219
+ end
220
+ end
221
+
222
+ context 'with a medium difficulty example' do
223
+ let(:report) do
224
+ {
225
+ 'a_spec.rb' => 1.0,
226
+ 'b_spec.rb' => 2.0,
227
+ 'c_spec.rb' => 3.0,
228
+ 'd_spec.rb' => 1.0,
229
+ 'e_spec.rb' => 2.0,
230
+ 'f_spec.rb' => 3.0,
231
+ 'g_spec.rb' => 1.0,
232
+ 'h_spec.rb' => 2.0,
233
+ 'i_spec.rb' => 3.0
234
+ }
235
+ end
236
+
237
+ it 'assigns all nodes equally' do
238
+ expect(node_weights.uniq).to contain_exactly 6.0
239
+ end
240
+ end
241
+
242
+ context 'with a difficult example' do
243
+ let(:report) do
244
+ {
245
+ 'a_spec.rb' => 2.0,
246
+ 'b_spec.rb' => 2.0,
247
+ 'c_spec.rb' => 3.0,
248
+ 'd_spec.rb' => 1.0,
249
+ 'e_spec.rb' => 1.0,
250
+ 'f_spec.rb' => 1.0,
251
+ 'g_spec.rb' => 9.0,
252
+ 'h_spec.rb' => 1.0,
253
+ 'i_spec.rb' => 10.0
254
+ }
255
+ end
256
+
257
+ it 'assigns all nodes equally' do
258
+ expect(node_weights.uniq).to contain_exactly 10.0
259
+ end
260
+ end
261
+ end
186
262
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-22 00:00:00.000000000 Z
11
+ date: 2021-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake