chef 11.14.0.alpha.2-x86-mingw32 → 11.14.0.alpha.3-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/chef-service-manager +1 -1
- data/lib/chef/application.rb +8 -2
- data/lib/chef/chef_fs/command_line.rb +4 -4
- data/lib/chef/chef_fs/file_system.rb +3 -3
- data/lib/chef/chef_fs/parallelizer.rb +66 -90
- data/lib/chef/chef_fs/parallelizer/flatten_enumerable.rb +35 -0
- data/lib/chef/chef_fs/parallelizer/parallel_enumerable.rb +279 -0
- data/lib/chef/config.rb +36 -2
- data/lib/chef/cookbook/cookbook_version_loader.rb +0 -1
- data/lib/chef/cookbook/synchronizer.rb +64 -42
- data/lib/chef/cookbook_uploader.rb +4 -25
- data/lib/chef/cookbook_version.rb +12 -11
- data/lib/chef/formatters/error_inspectors/api_error_formatting.rb +18 -1
- data/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb +1 -3
- data/lib/chef/knife/bootstrap.rb +23 -1
- data/lib/chef/knife/bootstrap/chef-aix.erb +58 -0
- data/lib/chef/knife/bootstrap/chef-full.erb +16 -13
- data/lib/chef/knife/core/bootstrap_context.rb +25 -1
- data/lib/chef/knife/list.rb +9 -8
- data/lib/chef/knife/serve.rb +44 -0
- data/lib/chef/knife/show.rb +2 -3
- data/lib/chef/knife/ssh.rb +1 -0
- data/lib/chef/mixin/create_path.rb +20 -4
- data/lib/chef/node.rb +19 -3
- data/lib/chef/platform/provider_mapping.rb +0 -1
- data/lib/chef/platform/query_helpers.rb +4 -3
- data/lib/chef/provider/env/windows.rb +10 -3
- data/lib/chef/provider/file.rb +1 -1
- data/lib/chef/provider/mount.rb +84 -42
- data/lib/chef/provider/package/freebsd/base.rb +92 -0
- data/lib/chef/provider/package/freebsd/pkg.rb +113 -0
- data/lib/chef/provider/package/freebsd/pkgng.rb +80 -0
- data/lib/chef/provider/package/freebsd/port.rb +70 -0
- data/lib/chef/providers.rb +3 -1
- data/lib/chef/resource/chef_gem.rb +2 -1
- data/lib/chef/resource/freebsd_package.rb +39 -3
- data/lib/chef/resource/lwrp_base.rb +2 -2
- data/lib/chef/resource/mount.rb +9 -9
- data/lib/chef/util/threaded_job_queue.rb +61 -0
- data/lib/chef/version.rb +1 -1
- data/lib/chef/version/platform.rb +2 -0
- data/lib/chef/whitelist.rb +82 -0
- data/lib/chef/win32/registry.rb +0 -1
- data/lib/chef/win32/version.rb +4 -3
- data/spec/functional/win32/versions_spec.rb +4 -4
- data/spec/integration/client/ipv6_spec.rb +1 -1
- data/spec/integration/knife/chef_fs_data_store_spec.rb +1 -1
- data/spec/integration/knife/chef_repo_path_spec.rb +4 -1
- data/spec/integration/knife/common_options_spec.rb +9 -9
- data/spec/integration/knife/cookbook_api_ipv6_spec.rb +2 -2
- data/spec/integration/knife/deps_spec.rb +3 -0
- data/spec/integration/knife/list_spec.rb +3 -0
- data/spec/integration/knife/raw_spec.rb +5 -2
- data/spec/integration/knife/redirection_spec.rb +4 -1
- data/spec/integration/knife/serve_spec.rb +57 -0
- data/spec/integration/knife/show_spec.rb +3 -0
- data/spec/support/pedant/run_pedant.rb +1 -0
- data/spec/support/platform_helpers.rb +7 -5
- data/spec/support/shared/context/config.rb +21 -0
- data/spec/support/shared/functional/file_resource.rb +52 -0
- data/spec/unit/chef_fs/parallelizer.rb +482 -0
- data/spec/unit/client_spec.rb +4 -2
- data/spec/unit/config_spec.rb +66 -12
- data/spec/unit/knife/bootstrap_spec.rb +6 -0
- data/spec/unit/knife/core/bootstrap_context_spec.rb +31 -1
- data/spec/unit/node_spec.rb +73 -3
- data/spec/unit/provider/mount_spec.rb +102 -79
- data/spec/unit/provider/package/{freebsd_spec.rb → freebsd/pkg_spec.rb} +19 -32
- data/spec/unit/provider/package/freebsd/pkgng_spec.rb +155 -0
- data/spec/unit/provider/package/freebsd/port_spec.rb +160 -0
- data/spec/unit/resource/chef_gem_spec.rb +5 -0
- data/spec/unit/resource/freebsd_package_spec.rb +63 -11
- data/spec/unit/resource/mount_spec.rb +11 -0
- data/spec/unit/role_spec.rb +5 -1
- data/spec/unit/run_lock_spec.rb +2 -0
- data/spec/unit/util/threaded_job_queue_spec.rb +51 -0
- data/spec/unit/version/platform_spec.rb +1 -1
- metadata +176 -161
- data/lib/chef/provider/package/freebsd.rb +0 -149
@@ -16,6 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
18
|
require 'support/shared/integration/integration_helper'
|
19
|
+
require 'support/shared/context/config'
|
19
20
|
require 'chef/knife/list'
|
20
21
|
|
21
22
|
describe 'redirection' do
|
@@ -23,13 +24,15 @@ describe 'redirection' do
|
|
23
24
|
include KnifeSupport
|
24
25
|
include AppServerSupport
|
25
26
|
|
27
|
+
include_context "default config options"
|
28
|
+
|
26
29
|
when_the_chef_server 'has a role' do
|
27
30
|
role 'x', {}
|
28
31
|
|
29
32
|
context 'and another server redirects to it with 302' do
|
30
33
|
before :each do
|
31
34
|
real_chef_server_url = Chef::Config.chef_server_url
|
32
|
-
Chef::Config.chef_server_url = "http://
|
35
|
+
Chef::Config.chef_server_url = "http://localhost:9018"
|
33
36
|
app = lambda do |env|
|
34
37
|
[302, {'Content-Type' => 'text','Location' => "#{real_chef_server_url}#{env['PATH_INFO']}" }, ['302 found'] ]
|
35
38
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#
|
2
|
+
# Author:: John Keiser (<jkeiser@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2013 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'support/shared/integration/integration_helper'
|
19
|
+
require 'chef/knife/serve'
|
20
|
+
require 'chef/server_api'
|
21
|
+
|
22
|
+
describe 'knife serve' do
|
23
|
+
extend IntegrationSupport
|
24
|
+
include KnifeSupport
|
25
|
+
include AppServerSupport
|
26
|
+
|
27
|
+
when_the_repository 'also has one of each thing' do
|
28
|
+
file 'nodes/x.json', { 'foo' => 'bar' }
|
29
|
+
|
30
|
+
it 'knife serve serves up /nodes/x' do
|
31
|
+
exception = nil
|
32
|
+
t = Thread.new do
|
33
|
+
begin
|
34
|
+
knife('serve')
|
35
|
+
rescue
|
36
|
+
exception = $!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
begin
|
40
|
+
Chef::Config.log_level = :debug
|
41
|
+
Chef::Config.chef_server_url = 'http://localhost:8889'
|
42
|
+
Chef::Config.node_name = nil
|
43
|
+
Chef::Config.client_key = nil
|
44
|
+
api = Chef::ServerAPI.new
|
45
|
+
api.get('nodes/x')['name'].should == 'x'
|
46
|
+
rescue
|
47
|
+
if exception
|
48
|
+
raise exception
|
49
|
+
else
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
ensure
|
53
|
+
t.kill
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -16,12 +16,15 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
18
|
require 'support/shared/integration/integration_helper'
|
19
|
+
require 'support/shared/context/config'
|
19
20
|
require 'chef/knife/show'
|
20
21
|
|
21
22
|
describe 'knife show' do
|
22
23
|
extend IntegrationSupport
|
23
24
|
include KnifeSupport
|
24
25
|
|
26
|
+
include_context "default config options"
|
27
|
+
|
25
28
|
when_the_chef_server "has one of each thing" do
|
26
29
|
client 'x', '{}'
|
27
30
|
cookbook 'x', '1.0.0', { 'metadata.rb' => 'version "1.0.0"' }
|
@@ -25,6 +25,7 @@ def start_server(chef_repo_path)
|
|
25
25
|
Chef::Config.versioned_cookbooks = true
|
26
26
|
chef_fs = Chef::ChefFS::Config.new.local_fs
|
27
27
|
data_store = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
|
28
|
+
data_store = ChefZero::DataStore::V1ToV2Adapter.new(data_store, 'chef', :org_defaults => ChefZero::DataStore::V1ToV2Adapter::ORG_DEFAULTS)
|
28
29
|
server = ChefZero::Server.new(:port => 8889, :data_store => data_store)#, :log_level => :debug)
|
29
30
|
server.start_background
|
30
31
|
server
|
@@ -27,18 +27,20 @@ def windows?
|
|
27
27
|
!!(RUBY_PLATFORM =~ /mswin|mingw|windows/)
|
28
28
|
end
|
29
29
|
|
30
|
-
require '
|
30
|
+
require 'wmi-lite/wmi' if windows?
|
31
31
|
|
32
32
|
def windows_domain_joined?
|
33
33
|
return false unless windows?
|
34
|
-
|
34
|
+
wmi = WmiLite::Wmi.new
|
35
|
+
computer_system = wmi.first_of('Win32_ComputerSystem')
|
36
|
+
computer_system['partofdomain']
|
35
37
|
end
|
36
38
|
|
37
39
|
def windows_win2k3?
|
38
40
|
return false unless windows?
|
39
|
-
|
40
|
-
host =
|
41
|
-
(host
|
41
|
+
wmi = WmiLite::Wmi.new
|
42
|
+
host = wmi.first_of('Win32_OperatingSystem')
|
43
|
+
(host['version'] && host['version'].start_with?("5.2"))
|
42
44
|
end
|
43
45
|
|
44
46
|
def mac_osx_106?
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Define config file setups for spec tests here.
|
4
|
+
# https://www.relishapp.com/rspec/rspec-core/docs/example-groups/shared-context
|
5
|
+
#
|
6
|
+
|
7
|
+
# Required chef files here:
|
8
|
+
require 'chef/config'
|
9
|
+
|
10
|
+
# Required spec files here:
|
11
|
+
require 'spec_helper'
|
12
|
+
|
13
|
+
# Basic config. Nothing fancy.
|
14
|
+
shared_context "default config options" do
|
15
|
+
before do
|
16
|
+
Chef::Config[:cache_path] = windows? ? 'C:\chef' : '/var/chef'
|
17
|
+
end
|
18
|
+
|
19
|
+
# Don't need to have an after block to reset the config...
|
20
|
+
# The spec_helper.rb takes care of resetting the config state.
|
21
|
+
end
|
@@ -645,6 +645,58 @@ shared_examples_for "a configured file resource" do
|
|
645
645
|
end
|
646
646
|
end
|
647
647
|
|
648
|
+
context "when the target file does not exist" do
|
649
|
+
before(:each) do
|
650
|
+
FileUtils.rm_rf(path)
|
651
|
+
end
|
652
|
+
|
653
|
+
after(:each) do
|
654
|
+
FileUtils.rm_rf(path)
|
655
|
+
end
|
656
|
+
|
657
|
+
def symlink?(file_path)
|
658
|
+
if windows?
|
659
|
+
Chef::ReservedNames::Win32::File.symlink?(file_path)
|
660
|
+
else
|
661
|
+
File.symlink?(file_path)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
def real_file?(file_path)
|
666
|
+
!symlink?(file_path) && File.file?(file_path)
|
667
|
+
end
|
668
|
+
|
669
|
+
describe "when force_unlink is set to true" do
|
670
|
+
it ":create updates the target" do
|
671
|
+
resource.force_unlink(true)
|
672
|
+
resource.run_action(:create)
|
673
|
+
real_file?(path).should be_true
|
674
|
+
binread(path).should == expected_content
|
675
|
+
resource.should be_updated_by_last_action
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
describe "when force_unlink is set to false" do
|
680
|
+
it ":create updates the target" do
|
681
|
+
resource.force_unlink(true)
|
682
|
+
resource.run_action(:create)
|
683
|
+
real_file?(path).should be_true
|
684
|
+
binread(path).should == expected_content
|
685
|
+
resource.should be_updated_by_last_action
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
describe "when force_unlink is not set (default)" do
|
690
|
+
it ":create updates the target" do
|
691
|
+
resource.force_unlink(true)
|
692
|
+
resource.run_action(:create)
|
693
|
+
real_file?(path).should be_true
|
694
|
+
binread(path).should == expected_content
|
695
|
+
resource.should be_updated_by_last_action
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
648
700
|
context "when the target file is a directory" do
|
649
701
|
before(:each) do
|
650
702
|
FileUtils.mkdir_p(path)
|
@@ -0,0 +1,482 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'chef/chef_fs/parallelizer'
|
3
|
+
|
4
|
+
describe Chef::ChefFS::Parallelizer do
|
5
|
+
before :each do
|
6
|
+
@start_time = Time.now
|
7
|
+
end
|
8
|
+
|
9
|
+
def elapsed_time
|
10
|
+
Time.now - @start_time
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
parallelizer.kill
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'With a Parallelizer with 5 threads' do
|
18
|
+
let :parallelizer do
|
19
|
+
Chef::ChefFS::Parallelizer.new(5)
|
20
|
+
end
|
21
|
+
|
22
|
+
def parallelize(inputs, options = {}, &block)
|
23
|
+
parallelizer.parallelize(inputs, { :main_thread_processing => false }.merge(options), &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "parallel_do creates unordered output as soon as it is available" do
|
27
|
+
outputs = []
|
28
|
+
parallelizer.parallel_do([0.5,0.3,0.1]) do |val|
|
29
|
+
sleep val
|
30
|
+
outputs << val
|
31
|
+
end
|
32
|
+
elapsed_time.should < 0.6
|
33
|
+
outputs.should == [ 0.1, 0.3, 0.5 ]
|
34
|
+
end
|
35
|
+
|
36
|
+
context "With :ordered => false (unordered output)" do
|
37
|
+
it "An empty input produces an empty output" do
|
38
|
+
parallelize([], :ordered => false) do
|
39
|
+
sleep 10
|
40
|
+
end.to_a == []
|
41
|
+
elapsed_time.should < 0.1
|
42
|
+
end
|
43
|
+
|
44
|
+
it "10 sleep(0.2)s complete within 0.5 seconds" do
|
45
|
+
parallelize(1.upto(10), :ordered => false) do |i|
|
46
|
+
sleep 0.2
|
47
|
+
'x'
|
48
|
+
end.to_a.should == %w(x x x x x x x x x x)
|
49
|
+
elapsed_time.should < 0.5
|
50
|
+
end
|
51
|
+
|
52
|
+
it "The output comes as soon as it is available" do
|
53
|
+
enum = parallelize([0.5,0.3,0.1], :ordered => false) do |val|
|
54
|
+
sleep val
|
55
|
+
val
|
56
|
+
end
|
57
|
+
enum.map do |value|
|
58
|
+
elapsed_time.should < value+0.1
|
59
|
+
value
|
60
|
+
end.should == [ 0.1, 0.3, 0.5 ]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "An exception in input is passed through but does NOT stop processing" do
|
64
|
+
input = TestEnumerable.new(0.5,0.3,0.1) do
|
65
|
+
raise 'hi'
|
66
|
+
end
|
67
|
+
enum = parallelize(input, :ordered => false) { |x| sleep(x); x }
|
68
|
+
results = []
|
69
|
+
expect { enum.each { |value| results << value } }.to raise_error 'hi'
|
70
|
+
results.should == [ 0.1, 0.3, 0.5 ]
|
71
|
+
elapsed_time.should < 0.6
|
72
|
+
end
|
73
|
+
|
74
|
+
it "Exceptions in output are raised after all processing is done" do
|
75
|
+
processed = 0
|
76
|
+
enum = parallelize([1,2,'x',3], :ordered => false) do |x|
|
77
|
+
if x == 'x'
|
78
|
+
sleep 0.1
|
79
|
+
raise 'hi'
|
80
|
+
end
|
81
|
+
sleep 0.2
|
82
|
+
processed += 1
|
83
|
+
x
|
84
|
+
end
|
85
|
+
results = []
|
86
|
+
expect { enum.each { |value| results << value } }.to raise_error 'hi'
|
87
|
+
results.sort.should == [ 1, 2, 3 ]
|
88
|
+
elapsed_time.should < 0.3
|
89
|
+
processed.should == 3
|
90
|
+
end
|
91
|
+
|
92
|
+
it "Exceptions with :stop_on_exception are raised after all processing is done" do
|
93
|
+
processed = 0
|
94
|
+
parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
|
95
|
+
if x == 'x'
|
96
|
+
sleep(0.1)
|
97
|
+
raise 'hi'
|
98
|
+
end
|
99
|
+
sleep(x)
|
100
|
+
processed += 1
|
101
|
+
x
|
102
|
+
end
|
103
|
+
expect { parallelized.to_a }.to raise_error 'hi'
|
104
|
+
processed.should == 4
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "With :ordered => true (ordered output)" do
|
109
|
+
it "An empty input produces an empty output" do
|
110
|
+
parallelize([]) do
|
111
|
+
sleep 10
|
112
|
+
end.to_a == []
|
113
|
+
elapsed_time.should < 0.1
|
114
|
+
end
|
115
|
+
|
116
|
+
it "10 sleep(0.2)s complete within 0.5 seconds" do
|
117
|
+
parallelize(1.upto(10), :ordered => true) do |i|
|
118
|
+
sleep 0.2
|
119
|
+
'x'
|
120
|
+
end.to_a.should == %w(x x x x x x x x x x)
|
121
|
+
elapsed_time.should < 0.5
|
122
|
+
end
|
123
|
+
|
124
|
+
it "Output comes in the order of the input" do
|
125
|
+
enum = parallelize([0.5,0.3,0.1]) do |val|
|
126
|
+
sleep val
|
127
|
+
val
|
128
|
+
end.enum_for(:each_with_index)
|
129
|
+
enum.next.should == [ 0.5, 0 ]
|
130
|
+
enum.next.should == [ 0.3, 1 ]
|
131
|
+
enum.next.should == [ 0.1, 2 ]
|
132
|
+
elapsed_time.should < 0.6
|
133
|
+
end
|
134
|
+
|
135
|
+
it "Exceptions in input are raised in the correct sequence but do NOT stop processing" do
|
136
|
+
input = TestEnumerable.new(0.5,0.3,0.1) do
|
137
|
+
raise 'hi'
|
138
|
+
end
|
139
|
+
results = []
|
140
|
+
enum = parallelize(input) { |x| sleep(x); x }
|
141
|
+
expect { enum.each { |value| results << value } }.to raise_error 'hi'
|
142
|
+
elapsed_time.should < 0.6
|
143
|
+
results.should == [ 0.5, 0.3, 0.1 ]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "Exceptions in output are raised in the correct sequence and running processes do NOT stop processing" do
|
147
|
+
processed = 0
|
148
|
+
enum = parallelize([1,2,'x',3]) do |x|
|
149
|
+
if x == 'x'
|
150
|
+
sleep(0.1)
|
151
|
+
raise 'hi'
|
152
|
+
end
|
153
|
+
sleep(0.2)
|
154
|
+
processed += 1
|
155
|
+
x
|
156
|
+
end
|
157
|
+
results = []
|
158
|
+
expect { enum.each { |value| results << value } }.to raise_error 'hi'
|
159
|
+
results.should == [ 1, 2 ]
|
160
|
+
elapsed_time.should < 0.3
|
161
|
+
processed.should == 3
|
162
|
+
end
|
163
|
+
|
164
|
+
it "Exceptions with :stop_on_exception are raised after all processing is done" do
|
165
|
+
processed = 0
|
166
|
+
parallelized = parallelize([0.3,0.3,'x',0.3,0.3,0.3,0.3,0.3], :ordered => false, :stop_on_exception => true) do |x|
|
167
|
+
if x == 'x'
|
168
|
+
sleep(0.1)
|
169
|
+
raise 'hi'
|
170
|
+
end
|
171
|
+
sleep(x)
|
172
|
+
processed += 1
|
173
|
+
x
|
174
|
+
end
|
175
|
+
expect { parallelized.to_a }.to raise_error 'hi'
|
176
|
+
processed.should == 4
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
it "When the input is slow, output still proceeds" do
|
181
|
+
input = TestEnumerable.new do |&block|
|
182
|
+
block.call(1)
|
183
|
+
sleep 0.1
|
184
|
+
block.call(2)
|
185
|
+
sleep 0.1
|
186
|
+
block.call(3)
|
187
|
+
sleep 0.1
|
188
|
+
end
|
189
|
+
enum = parallelize(input) { |x| x }
|
190
|
+
enum.map do |value|
|
191
|
+
elapsed_time.should < (value+1)*0.1
|
192
|
+
value
|
193
|
+
end.should == [ 1, 2, 3 ]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "With a Parallelizer with 1 thread" do
|
198
|
+
let :parallelizer do
|
199
|
+
Chef::ChefFS::Parallelizer.new(1)
|
200
|
+
end
|
201
|
+
|
202
|
+
context "when the thread is occupied with a job" do
|
203
|
+
before :each do
|
204
|
+
parallelizer
|
205
|
+
started = false
|
206
|
+
@occupying_job_finished = occupying_job_finished = [ false ]
|
207
|
+
@thread = Thread.new do
|
208
|
+
begin
|
209
|
+
parallelizer.parallelize([0], :main_thread_processing => false) do |x|
|
210
|
+
started = true
|
211
|
+
sleep(0.3)
|
212
|
+
occupying_job_finished[0] = true
|
213
|
+
end.wait
|
214
|
+
ensure
|
215
|
+
end
|
216
|
+
end
|
217
|
+
while !started
|
218
|
+
sleep(0.01)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
after :each do
|
223
|
+
if RUBY_VERSION.to_f > 1.8
|
224
|
+
Thread.kill(@thread)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
it "parallelize with :main_thread_processing = true does not block" do
|
229
|
+
parallelizer.parallelize([1]) do |x|
|
230
|
+
sleep(0.1)
|
231
|
+
x
|
232
|
+
end.to_a.should == [ 1 ]
|
233
|
+
elapsed_time.should < 0.2
|
234
|
+
end
|
235
|
+
|
236
|
+
it "parallelize with :main_thread_processing = false waits for the job to finish" do
|
237
|
+
parallelizer.parallelize([1], :main_thread_processing => false) do |x|
|
238
|
+
sleep(0.1)
|
239
|
+
x+1
|
240
|
+
end.to_a.should == [ 2 ]
|
241
|
+
elapsed_time.should > 0.3
|
242
|
+
end
|
243
|
+
|
244
|
+
it "resizing the Parallelizer to 0 waits for the job to stop" do
|
245
|
+
elapsed_time.should < 0.2
|
246
|
+
parallelizer.resize(0)
|
247
|
+
parallelizer.num_threads.should == 0
|
248
|
+
elapsed_time.should > 0.25
|
249
|
+
@occupying_job_finished.should == [ true ]
|
250
|
+
end
|
251
|
+
|
252
|
+
it "stopping the Parallelizer waits for the job to finish" do
|
253
|
+
elapsed_time.should < 0.2
|
254
|
+
parallelizer.stop
|
255
|
+
parallelizer.num_threads.should == 0
|
256
|
+
elapsed_time.should > 0.25
|
257
|
+
@occupying_job_finished.should == [ true ]
|
258
|
+
end
|
259
|
+
|
260
|
+
it "resizing the Parallelizer to 2 does not stop the job" do
|
261
|
+
elapsed_time.should < 0.2
|
262
|
+
parallelizer.resize(2)
|
263
|
+
parallelizer.num_threads.should == 2
|
264
|
+
elapsed_time.should < 0.2
|
265
|
+
sleep(0.3)
|
266
|
+
@occupying_job_finished.should == [ true ]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "enumerable methods should run efficiently" do
|
271
|
+
it ".count does not process anything" do
|
272
|
+
outputs_processed = 0
|
273
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
274
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
275
|
+
outputs_processed += 1
|
276
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
277
|
+
x
|
278
|
+
end
|
279
|
+
enum.count.should == 6
|
280
|
+
outputs_processed.should == 0
|
281
|
+
input_mapper.num_processed.should == 6
|
282
|
+
end
|
283
|
+
|
284
|
+
it ".count with arguments works normally" do
|
285
|
+
outputs_processed = 0
|
286
|
+
input_mapper = TestEnumerable.new(1,1,1,1,2,2,2,3,3,4)
|
287
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
288
|
+
outputs_processed += 1
|
289
|
+
x
|
290
|
+
end
|
291
|
+
enum.count { |x| x > 1 }.should == 6
|
292
|
+
enum.count(2).should == 3
|
293
|
+
outputs_processed.should == 20
|
294
|
+
input_mapper.num_processed.should == 20
|
295
|
+
end
|
296
|
+
|
297
|
+
it ".first does not enumerate anything other than the first result(s)" do
|
298
|
+
outputs_processed = 0
|
299
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
300
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
301
|
+
outputs_processed += 1
|
302
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
303
|
+
x
|
304
|
+
end
|
305
|
+
enum.first.should == 1
|
306
|
+
enum.first(2).should == [1,2]
|
307
|
+
outputs_processed.should == 3
|
308
|
+
input_mapper.num_processed.should == 3
|
309
|
+
end
|
310
|
+
|
311
|
+
it ".take does not enumerate anything other than the first result(s)" do
|
312
|
+
outputs_processed = 0
|
313
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
314
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
315
|
+
outputs_processed += 1
|
316
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
317
|
+
x
|
318
|
+
end
|
319
|
+
enum.take(2).should == [1,2]
|
320
|
+
outputs_processed.should == 2
|
321
|
+
input_mapper.num_processed.should == 2
|
322
|
+
end
|
323
|
+
|
324
|
+
it ".drop does not process anything other than the last result(s)" do
|
325
|
+
outputs_processed = 0
|
326
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
327
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
328
|
+
outputs_processed += 1
|
329
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
330
|
+
x
|
331
|
+
end
|
332
|
+
enum.drop(2).should == [3,4,5,6]
|
333
|
+
outputs_processed.should == 4
|
334
|
+
input_mapper.num_processed.should == 6
|
335
|
+
end
|
336
|
+
|
337
|
+
if Enumerable.method_defined?(:lazy)
|
338
|
+
it ".lazy.take does not enumerate anything other than the first result(s)" do
|
339
|
+
outputs_processed = 0
|
340
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
341
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
342
|
+
outputs_processed += 1
|
343
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
344
|
+
x
|
345
|
+
end
|
346
|
+
enum.lazy.take(2).to_a.should == [1,2]
|
347
|
+
outputs_processed.should == 2
|
348
|
+
input_mapper.num_processed.should == 2
|
349
|
+
end
|
350
|
+
|
351
|
+
it ".drop does not process anything other than the last result(s)" do
|
352
|
+
outputs_processed = 0
|
353
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
354
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
355
|
+
outputs_processed += 1
|
356
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
357
|
+
x
|
358
|
+
end
|
359
|
+
enum.lazy.drop(2).to_a.should == [3,4,5,6]
|
360
|
+
outputs_processed.should == 4
|
361
|
+
input_mapper.num_processed.should == 6
|
362
|
+
end
|
363
|
+
|
364
|
+
it "lazy enumerable is actually lazy" do
|
365
|
+
outputs_processed = 0
|
366
|
+
input_mapper = TestEnumerable.new(1,2,3,4,5,6)
|
367
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
368
|
+
outputs_processed += 1
|
369
|
+
sleep(0.05) # Just enough to yield and get other inputs in the queue
|
370
|
+
x
|
371
|
+
end
|
372
|
+
enum.lazy.take(2)
|
373
|
+
enum.lazy.drop(2)
|
374
|
+
sleep(0.1)
|
375
|
+
outputs_processed.should == 0
|
376
|
+
input_mapper.num_processed.should == 0
|
377
|
+
end
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
context "running enumerable multiple times should function correctly" do
|
382
|
+
it ".map twice on the same parallel enumerable returns the correct results and re-processes the input" do
|
383
|
+
outputs_processed = 0
|
384
|
+
input_mapper = TestEnumerable.new(1,2,3)
|
385
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
386
|
+
outputs_processed += 1
|
387
|
+
x
|
388
|
+
end
|
389
|
+
enum.map { |x| x }.should == [1,2,3]
|
390
|
+
enum.map { |x| x }.should == [1,2,3]
|
391
|
+
outputs_processed.should == 6
|
392
|
+
input_mapper.num_processed.should == 6
|
393
|
+
end
|
394
|
+
|
395
|
+
it ".first and then .map on the same parallel enumerable returns the correct results and re-processes the input" do
|
396
|
+
outputs_processed = 0
|
397
|
+
input_mapper = TestEnumerable.new(1,2,3)
|
398
|
+
enum = parallelizer.parallelize(input_mapper) do |x|
|
399
|
+
outputs_processed += 1
|
400
|
+
x
|
401
|
+
end
|
402
|
+
enum.first.should == 1
|
403
|
+
enum.map { |x| x }.should == [1,2,3]
|
404
|
+
outputs_processed.should >= 4
|
405
|
+
input_mapper.num_processed.should >= 4
|
406
|
+
end
|
407
|
+
|
408
|
+
it "two simultaneous enumerations throws an exception" do
|
409
|
+
enum = parallelizer.parallelize([1,2,3]) { |x| x }
|
410
|
+
a = enum.enum_for(:each)
|
411
|
+
a.next
|
412
|
+
expect do
|
413
|
+
b = enum.enum_for(:each)
|
414
|
+
b.next
|
415
|
+
end.to raise_error
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
context "With a Parallelizer with 0 threads" do
|
421
|
+
let :parallelizer do
|
422
|
+
Chef::ChefFS::Parallelizer.new(0)
|
423
|
+
end
|
424
|
+
|
425
|
+
context "And main_thread_processing on" do
|
426
|
+
it "succeeds in running" do
|
427
|
+
parallelizer.parallelize([0.5]) { |x| x*2 }.to_a.should == [1]
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
context "With a Parallelizer with 10 threads" do
|
433
|
+
let :parallelizer do
|
434
|
+
Chef::ChefFS::Parallelizer.new(10)
|
435
|
+
end
|
436
|
+
|
437
|
+
it "does not have contention issues with large numbers of inputs" do
|
438
|
+
parallelizer.parallelize(1.upto(500)) { |x| x+1 }.to_a.should == 2.upto(501).to_a
|
439
|
+
end
|
440
|
+
|
441
|
+
it "does not have contention issues with large numbers of inputs with ordering off" do
|
442
|
+
parallelizer.parallelize(1.upto(500), :ordered => false) { |x| x+1 }.to_a.sort.should == 2.upto(501).to_a
|
443
|
+
end
|
444
|
+
|
445
|
+
it "does not have contention issues with large numbers of jobs and inputs with ordering off" do
|
446
|
+
parallelizers = 0.upto(99).map do
|
447
|
+
parallelizer.parallelize(1.upto(500)) { |x| x+1 }
|
448
|
+
end
|
449
|
+
outputs = []
|
450
|
+
threads = 0.upto(99).map do |i|
|
451
|
+
Thread.new { outputs[i] = parallelizers[i].to_a }
|
452
|
+
end
|
453
|
+
threads.each { |thread| thread.join }
|
454
|
+
outputs.each { |output| output.sort.should == 2.upto(501).to_a }
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
class TestEnumerable
|
459
|
+
include Enumerable
|
460
|
+
|
461
|
+
def initialize(*values, &block)
|
462
|
+
@values = values
|
463
|
+
@block = block
|
464
|
+
@num_processed = 0
|
465
|
+
end
|
466
|
+
|
467
|
+
attr_reader :num_processed
|
468
|
+
|
469
|
+
def each(&each_block)
|
470
|
+
@values.each do |value|
|
471
|
+
@num_processed += 1
|
472
|
+
each_block.call(value)
|
473
|
+
end
|
474
|
+
if @block
|
475
|
+
@block.call do |value|
|
476
|
+
@num_processed += 1
|
477
|
+
each_block.call(value)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|