knapsack 0.0.3 → 0.1.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/.travis.yml +12 -1
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +1 -1
- data/README.md +71 -24
- data/Rakefile +3 -1
- data/TODO.md +5 -0
- data/knapsack_report.json +9 -12
- data/lib/knapsack.rb +25 -6
- data/lib/knapsack/adapters/{base.rb → base_adapter.rb} +18 -8
- data/lib/knapsack/adapters/{rspec.rb → rspec_adapter.rb} +13 -6
- data/lib/knapsack/allocator.rb +65 -0
- data/lib/knapsack/distributors/base_distributor.rb +67 -0
- data/lib/knapsack/distributors/leftover_distributor.rb +49 -0
- data/lib/knapsack/distributors/report_distributor.rb +76 -0
- data/lib/knapsack/presenter.rb +38 -5
- data/lib/knapsack/report.rb +27 -12
- data/lib/knapsack/task_loader.rb +11 -0
- data/lib/knapsack/tracker.rb +30 -13
- data/lib/knapsack/version.rb +1 -1
- data/lib/tasks/knapsack.rake +21 -0
- data/spec/knapsack/adapters/base_adapter_spec.rb +91 -0
- data/spec/knapsack/adapters/rspec_adapter_spec.rb +29 -0
- data/spec/knapsack/allocator_spec.rb +57 -0
- data/spec/knapsack/distributors/base_distributor_spec.rb +85 -0
- data/spec/knapsack/distributors/leftover_distributor_spec.rb +110 -0
- data/spec/knapsack/distributors/report_distributor_spec.rb +152 -0
- data/spec/knapsack/presenter_spec.rb +83 -0
- data/spec/knapsack/report_spec.rb +73 -0
- data/spec/knapsack/task_loader_spec.rb +10 -0
- data/spec/knapsack/tracker_spec.rb +84 -20
- data/spec/knapsack_spec.rb +23 -2
- data/spec/spec_helper.rb +16 -0
- data/spec_examples/fast/1_spec.rb +1 -4
- data/spec_examples/fast/2_spec.rb +1 -4
- data/spec_examples/fast/3_spec.rb +1 -4
- data/spec_examples/fast/4_spec.rb +1 -4
- data/spec_examples/fast/5_spec.rb +1 -4
- data/spec_examples/fast/6_spec.rb +1 -4
- data/spec_examples/leftover/1_spec.rb +4 -0
- data/spec_examples/leftover/a_spec.rb +8 -0
- data/spec_examples/slow/a_spec.rb +1 -3
- data/spec_examples/slow/b_spec.rb +3 -5
- data/spec_examples/slow/c_spec.rb +1 -3
- data/spec_examples/spec_helper.rb +5 -2
- metadata +32 -7
- data/spec_examples/slow/d_spec.rb +0 -7
- data/spec_examples/slow/e_spec.rb +0 -7
- data/spec_examples/slow/f_spec.rb +0 -7
@@ -0,0 +1,29 @@
|
|
1
|
+
describe Knapsack::Adapters::RspecAdapter do
|
2
|
+
before do
|
3
|
+
expect(::RSpec).to receive(:configure)
|
4
|
+
end
|
5
|
+
|
6
|
+
describe '#bind_time_tracker' do
|
7
|
+
it do
|
8
|
+
expect {
|
9
|
+
subject.bind_time_tracker
|
10
|
+
}.not_to raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#bind_report_generator' do
|
15
|
+
it do
|
16
|
+
expect {
|
17
|
+
subject.bind_report_generator
|
18
|
+
}.not_to raise_error
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#bind_time_offset_warning' do
|
23
|
+
it do
|
24
|
+
expect {
|
25
|
+
subject.bind_time_offset_warning
|
26
|
+
}.not_to raise_error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
describe Knapsack::Allocator do
|
2
|
+
let(:spec_pattern) { nil }
|
3
|
+
let(:args) do
|
4
|
+
{
|
5
|
+
ci_node_total: nil,
|
6
|
+
ci_node_index: nil,
|
7
|
+
spec_pattern: spec_pattern,
|
8
|
+
report: nil
|
9
|
+
}
|
10
|
+
end
|
11
|
+
let(:report_distributor) { instance_double(Knapsack::Distributors::ReportDistributor) }
|
12
|
+
let(:leftover_distributor) { instance_double(Knapsack::Distributors::LeftoverDistributor) }
|
13
|
+
let(:report_specs) { ['a_spec.rb', 'b_spec.rb'] }
|
14
|
+
let(:leftover_specs) { ['c_spec.rb', 'd_spec.rb'] }
|
15
|
+
let(:node_specs) { report_specs + leftover_specs }
|
16
|
+
let(:allocator) { described_class.new(args) }
|
17
|
+
|
18
|
+
before do
|
19
|
+
expect(Knapsack::Distributors::ReportDistributor).to receive(:new).with(args).and_return(report_distributor)
|
20
|
+
expect(Knapsack::Distributors::LeftoverDistributor).to receive(:new).with(args).and_return(leftover_distributor)
|
21
|
+
allow(report_distributor).to receive(:specs_for_current_node).and_return(report_specs)
|
22
|
+
allow(leftover_distributor).to receive(:specs_for_current_node).and_return(leftover_specs)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#report_node_specs' do
|
26
|
+
subject { allocator.report_node_specs }
|
27
|
+
it { should eql report_specs }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#leftover_node_specs' do
|
31
|
+
subject { allocator.leftover_node_specs }
|
32
|
+
it { should eql leftover_specs }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#node_specs' do
|
36
|
+
subject { allocator.node_specs }
|
37
|
+
it { should eql node_specs }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#stringify_node_specs' do
|
41
|
+
subject { allocator.stringify_node_specs }
|
42
|
+
it { should eql node_specs.join(' ') }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#custom_spec_dir' do
|
46
|
+
subject { allocator.custom_spec_dir }
|
47
|
+
|
48
|
+
context 'when spec pattern exists' do
|
49
|
+
let(:spec_pattern) { "custom_spec_dir/**/*_spec.rb" }
|
50
|
+
it { should eql 'custom_spec_dir/' }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when spec pattern doesn't exist" do
|
54
|
+
it { should be_nil }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
describe Knapsack::Distributors::BaseDistributor do
|
2
|
+
let(:args) { {} }
|
3
|
+
let(:default_report) { { 'default_report_spec.rb' => 1.0 } }
|
4
|
+
|
5
|
+
let(:distributor) { described_class.new(args) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Knapsack).to receive(:report) {
|
9
|
+
instance_double(Knapsack::Report, open: default_report)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#report' do
|
14
|
+
subject { distributor.report }
|
15
|
+
|
16
|
+
context 'when report is given' do
|
17
|
+
let(:report) { { 'a_spec.rb' => 2.0 } }
|
18
|
+
let(:args) { { report: report } }
|
19
|
+
|
20
|
+
it { should eql(report) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when report is not given' do
|
24
|
+
it { should eql(default_report) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#ci_node_total' do
|
29
|
+
subject { distributor.ci_node_total }
|
30
|
+
|
31
|
+
context 'when ci_node_total is given' do
|
32
|
+
let(:args) { { ci_node_total: 4 } }
|
33
|
+
|
34
|
+
it { should eql 4 }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when ci_node_total is not given' do
|
38
|
+
it { should eql 1 }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#ci_node_index' do
|
43
|
+
subject { distributor.ci_node_index }
|
44
|
+
|
45
|
+
context 'when ci_node_index is given' do
|
46
|
+
let(:args) { { ci_node_index: 3 } }
|
47
|
+
|
48
|
+
it { should eql 3 }
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when ci_node_index is not given' do
|
52
|
+
it { should eql 0 }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#specs_for_current_node' do
|
57
|
+
let(:args) do
|
58
|
+
{
|
59
|
+
ci_node_total: 3,
|
60
|
+
ci_node_index: ci_node_index
|
61
|
+
}
|
62
|
+
end
|
63
|
+
let(:specs) { double }
|
64
|
+
|
65
|
+
subject { distributor.specs_for_current_node }
|
66
|
+
|
67
|
+
context 'when ci_node_index not set' do
|
68
|
+
let(:ci_node_index) { nil }
|
69
|
+
|
70
|
+
it do
|
71
|
+
expect(distributor).to receive(:specs_for_node).with(0).and_return(specs)
|
72
|
+
expect(subject).to eql specs
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when ci_node_index set' do
|
77
|
+
let(:ci_node_index) { 2 }
|
78
|
+
|
79
|
+
it do
|
80
|
+
expect(distributor).to receive(:specs_for_node).with(ci_node_index).and_return(specs)
|
81
|
+
expect(subject).to eql specs
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
describe Knapsack::Distributors::LeftoverDistributor do
|
2
|
+
let(:args) { {} }
|
3
|
+
let(:default_report) do
|
4
|
+
{
|
5
|
+
'a_spec.rb' => 1.0,
|
6
|
+
'b_spec.rb' => 1.5,
|
7
|
+
'c_spec.rb' => 2.0,
|
8
|
+
'd_spec.rb' => 2.5,
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:distributor) { described_class.new(args) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
allow(Knapsack).to receive(:report) {
|
16
|
+
instance_double(Knapsack::Report, open: default_report)
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#report_specs' do
|
21
|
+
subject { distributor.report_specs }
|
22
|
+
it { should eql ['a_spec.rb', 'b_spec.rb', 'c_spec.rb', 'd_spec.rb'] }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#all_specs' do
|
26
|
+
subject { distributor.all_specs }
|
27
|
+
|
28
|
+
context 'when default spec pattern' do
|
29
|
+
it { should_not be_empty }
|
30
|
+
it { should include 'spec/knapsack/tracker_spec.rb' }
|
31
|
+
it { should include 'spec/knapsack/adapters/rspec_adapter_spec.rb' }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when fake spec pattern' do
|
35
|
+
let(:args) { { spec_pattern: 'fake_pattern' } }
|
36
|
+
it { should be_empty }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#leftover_specs' do
|
41
|
+
subject { distributor.leftover_specs }
|
42
|
+
|
43
|
+
before do
|
44
|
+
expect(distributor).to receive(:all_specs).and_return([
|
45
|
+
'a_spec.rb',
|
46
|
+
'b_spec.rb',
|
47
|
+
'c_spec.rb',
|
48
|
+
'd_spec.rb',
|
49
|
+
'e_spec.rb',
|
50
|
+
'f_spec.rb',
|
51
|
+
])
|
52
|
+
end
|
53
|
+
|
54
|
+
it { should eql ['e_spec.rb', 'f_spec.rb'] }
|
55
|
+
end
|
56
|
+
|
57
|
+
context do
|
58
|
+
let(:args) { { ci_node_total: 3 } }
|
59
|
+
let(:leftover_specs) {[
|
60
|
+
'a_spec.rb',
|
61
|
+
'b_spec.rb',
|
62
|
+
'c_spec.rb',
|
63
|
+
'd_spec.rb',
|
64
|
+
'e_spec.rb',
|
65
|
+
'f_spec.rb',
|
66
|
+
'g_spec.rb',
|
67
|
+
]}
|
68
|
+
|
69
|
+
before do
|
70
|
+
expect(distributor).to receive(:leftover_specs).and_return(leftover_specs)
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#assign_spec_files_to_node' do
|
74
|
+
before do
|
75
|
+
distributor.assign_spec_files_to_node
|
76
|
+
end
|
77
|
+
|
78
|
+
it do
|
79
|
+
expect(distributor.node_specs[0]).to eql([
|
80
|
+
'a_spec.rb',
|
81
|
+
'd_spec.rb',
|
82
|
+
'g_spec.rb',
|
83
|
+
])
|
84
|
+
end
|
85
|
+
|
86
|
+
it do
|
87
|
+
expect(distributor.node_specs[1]).to eql([
|
88
|
+
'b_spec.rb',
|
89
|
+
'e_spec.rb',
|
90
|
+
])
|
91
|
+
end
|
92
|
+
|
93
|
+
it do
|
94
|
+
expect(distributor.node_specs[2]).to eql([
|
95
|
+
'c_spec.rb',
|
96
|
+
'f_spec.rb',
|
97
|
+
])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#specs_for_node' do
|
102
|
+
it do
|
103
|
+
expect(distributor.specs_for_node(1)).to eql([
|
104
|
+
'b_spec.rb',
|
105
|
+
'e_spec.rb',
|
106
|
+
])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
describe Knapsack::Distributors::ReportDistributor do
|
2
|
+
let(:args) { {} }
|
3
|
+
let(:default_report) { { 'default_report_spec.rb' => 1.0 } }
|
4
|
+
|
5
|
+
let(:distributor) { described_class.new(args) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(Knapsack).to receive(:report) {
|
9
|
+
instance_double(Knapsack::Report, open: default_report)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#sorted_report' do
|
14
|
+
subject { distributor.sorted_report }
|
15
|
+
|
16
|
+
let(:report) do
|
17
|
+
{
|
18
|
+
'e_spec.rb' => 3.0,
|
19
|
+
'f_spec.rb' => 3.5,
|
20
|
+
'c_spec.rb' => 2.0,
|
21
|
+
'd_spec.rb' => 2.5,
|
22
|
+
'a_spec.rb' => 1.0,
|
23
|
+
'b_spec.rb' => 1.5,
|
24
|
+
}
|
25
|
+
end
|
26
|
+
let(:args) { { report: report } }
|
27
|
+
|
28
|
+
it do
|
29
|
+
should eql([
|
30
|
+
["f_spec.rb", 3.5],
|
31
|
+
["e_spec.rb", 3.0],
|
32
|
+
["d_spec.rb", 2.5],
|
33
|
+
["c_spec.rb", 2.0],
|
34
|
+
["b_spec.rb", 1.5],
|
35
|
+
["a_spec.rb", 1.0],
|
36
|
+
])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context do
|
41
|
+
let(:report) do
|
42
|
+
{
|
43
|
+
'a_spec.rb' => 3.0,
|
44
|
+
'b_spec.rb' => 1.0,
|
45
|
+
'c_spec.rb' => 1.5,
|
46
|
+
}
|
47
|
+
end
|
48
|
+
let(:args) { { report: report } }
|
49
|
+
|
50
|
+
describe '#total_time_execution' do
|
51
|
+
subject { distributor.total_time_execution }
|
52
|
+
|
53
|
+
context 'when time is float' do
|
54
|
+
it { should eql 5.5 }
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when time is not float' do
|
58
|
+
let(:report) do
|
59
|
+
{
|
60
|
+
'a_spec.rb' => 3,
|
61
|
+
'b_spec.rb' => 1,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
it { should eql 4.0 }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#node_time_execution' do
|
70
|
+
subject { distributor.node_time_execution }
|
71
|
+
let(:args) { { report: report, ci_node_total: 4 } }
|
72
|
+
it { should eql 1.375 }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context do
|
77
|
+
let(:report) do
|
78
|
+
{
|
79
|
+
'g_spec.rb' => 9.0,
|
80
|
+
'h_spec.rb' => 3.0,
|
81
|
+
'i_spec.rb' => 3.0,
|
82
|
+
'f_spec.rb' => 3.5,
|
83
|
+
'c_spec.rb' => 2.0,
|
84
|
+
'd_spec.rb' => 2.5,
|
85
|
+
'a_spec.rb' => 1.0,
|
86
|
+
'b_spec.rb' => 1.5,
|
87
|
+
}
|
88
|
+
end
|
89
|
+
let(:args) do
|
90
|
+
{
|
91
|
+
report: report,
|
92
|
+
ci_node_total: 3,
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#assign_spec_files_to_node' do
|
97
|
+
before { distributor.assign_spec_files_to_node }
|
98
|
+
|
99
|
+
it do
|
100
|
+
expect(distributor.node_specs[0]).to eql({
|
101
|
+
:node_index => 0,
|
102
|
+
:time_left => -0.5,
|
103
|
+
:spec_files_with_time => [
|
104
|
+
["g_spec.rb", 9.0]
|
105
|
+
]
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
109
|
+
it do
|
110
|
+
expect(distributor.node_specs[1]).to eql({
|
111
|
+
:node_index => 1,
|
112
|
+
:time_left => 0.0,
|
113
|
+
:spec_files_with_time => [
|
114
|
+
["f_spec.rb", 3.5],
|
115
|
+
["d_spec.rb", 2.5],
|
116
|
+
["a_spec.rb", 1.0],
|
117
|
+
["b_spec.rb", 1.5]
|
118
|
+
]
|
119
|
+
})
|
120
|
+
end
|
121
|
+
|
122
|
+
it do
|
123
|
+
expect(distributor.node_specs[2]).to eql({
|
124
|
+
:node_index => 2,
|
125
|
+
:time_left => 0.5,
|
126
|
+
:spec_files_with_time => [
|
127
|
+
["h_spec.rb", 3.0],
|
128
|
+
["c_spec.rb", 2.0],
|
129
|
+
["i_spec.rb", 3.0]
|
130
|
+
]
|
131
|
+
})
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe '#specs_for_node' do
|
136
|
+
context 'when node exists' do
|
137
|
+
it do
|
138
|
+
expect(distributor.specs_for_node(1)).to eql([
|
139
|
+
'f_spec.rb',
|
140
|
+
'd_spec.rb',
|
141
|
+
'a_spec.rb',
|
142
|
+
'b_spec.rb'
|
143
|
+
])
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when node doesn't exist" do
|
148
|
+
it { expect(distributor.specs_for_node(42)).to be_nil }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
describe Knapsack::Presenter do
|
2
|
+
let(:tracker) { instance_double(Knapsack::Tracker) }
|
3
|
+
let(:spec_files_with_time) do
|
4
|
+
{
|
5
|
+
'a_spec.rb' => 1.0,
|
6
|
+
'b_spec.rb' => 0.4
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'report methods' do
|
11
|
+
before do
|
12
|
+
expect(Knapsack).to receive(:tracker) { tracker }
|
13
|
+
expect(tracker).to receive(:spec_files_with_time).and_return(spec_files_with_time)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.report_yml' do
|
17
|
+
subject { described_class.report_yml }
|
18
|
+
it { should eql spec_files_with_time.to_yaml }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.report_json' do
|
22
|
+
subject { described_class.report_json }
|
23
|
+
it { should eql JSON.pretty_generate(spec_files_with_time) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.global_time' do
|
28
|
+
subject { described_class.global_time }
|
29
|
+
|
30
|
+
before do
|
31
|
+
expect(Knapsack).to receive(:tracker) { tracker }
|
32
|
+
expect(tracker).to receive(:global_time).and_return(4.2)
|
33
|
+
end
|
34
|
+
|
35
|
+
it { should eql "\nKnapsack global time execution for specs: 4.2s" }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '.report_details' do
|
39
|
+
subject { described_class.report_details }
|
40
|
+
|
41
|
+
before do
|
42
|
+
expect(described_class).to receive(:report_json).and_return('{}')
|
43
|
+
end
|
44
|
+
|
45
|
+
it { should eql "Knapsack report was generated. Preview:\n{}" }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '.time_offset_warning' do
|
49
|
+
let(:time_offset_in_seconds) { 30 }
|
50
|
+
let(:max_node_time_execution) { 60 }
|
51
|
+
let(:exceeded_time) { 3 }
|
52
|
+
|
53
|
+
subject { described_class.time_offset_warning }
|
54
|
+
|
55
|
+
before do
|
56
|
+
allow(Knapsack).to receive(:tracker) { tracker }
|
57
|
+
expect(tracker).to receive(:config).and_return({time_offset_in_seconds: time_offset_in_seconds})
|
58
|
+
expect(tracker).to receive(:max_node_time_execution).and_return(max_node_time_execution)
|
59
|
+
expect(tracker).to receive(:exceeded_time).and_return(exceeded_time)
|
60
|
+
expect(tracker).to receive(:time_exceeded?).and_return(time_exceeded?)
|
61
|
+
end
|
62
|
+
|
63
|
+
shared_examples 'knapsack time offset warning' do
|
64
|
+
it { should include 'Time offset: 30s' }
|
65
|
+
it { should include 'Max allowed node time execution: 60s' }
|
66
|
+
it { should include 'Exceeded time: 3s' }
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when time exceeded' do
|
70
|
+
let(:time_exceeded?) { true }
|
71
|
+
|
72
|
+
it_behaves_like 'knapsack time offset warning'
|
73
|
+
it { should include 'Please regenerate your knapsack report.' }
|
74
|
+
end
|
75
|
+
|
76
|
+
context "when time did not exceed" do
|
77
|
+
let(:time_exceeded?) { false }
|
78
|
+
|
79
|
+
it_behaves_like 'knapsack time offset warning'
|
80
|
+
it { should include 'Global time execution for this CI node is fine.' }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|