chef 12.2.1 → 12.3.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef.rb +1 -0
  3. data/lib/chef/application/apply.rb +5 -0
  4. data/lib/chef/application/client.rb +10 -0
  5. data/lib/chef/application/knife.rb +5 -1
  6. data/lib/chef/application/solo.rb +5 -0
  7. data/lib/chef/chef_class.rb +130 -0
  8. data/lib/chef/client.rb +15 -7
  9. data/lib/chef/config.rb +13 -0
  10. data/lib/chef/event_loggers/windows_eventlog.rb +11 -5
  11. data/lib/chef/http.rb +13 -3
  12. data/lib/chef/http/basic_client.rb +21 -4
  13. data/lib/chef/http/socketless_chef_zero_client.rb +207 -0
  14. data/lib/chef/knife.rb +3 -0
  15. data/lib/chef/knife/bootstrap.rb +1 -1
  16. data/lib/chef/knife/core/status_presenter.rb +12 -11
  17. data/lib/chef/knife/ssh.rb +3 -1
  18. data/lib/chef/knife/status.rb +32 -7
  19. data/lib/chef/local_mode.rb +13 -3
  20. data/lib/chef/mixin/provides.rb +32 -0
  21. data/lib/chef/platform/provider_priority_map.rb +16 -7
  22. data/lib/chef/platform/resource_priority_map.rb +37 -0
  23. data/lib/chef/policy_builder/expand_node_object.rb +14 -0
  24. data/lib/chef/policy_builder/policyfile.rb +0 -1
  25. data/lib/chef/provider.rb +5 -20
  26. data/lib/chef/provider/package/rubygems.rb +4 -1
  27. data/lib/chef/provider/service/macosx.rb +66 -30
  28. data/lib/chef/provider_resolver.rb +10 -5
  29. data/lib/chef/resource.rb +5 -39
  30. data/lib/chef/resource/gem_package.rb +5 -0
  31. data/lib/chef/resource/link.rb +1 -1
  32. data/lib/chef/resource/macosx_service.rb +59 -0
  33. data/lib/chef/resource/remote_file.rb +0 -4
  34. data/lib/chef/resource_resolver.rb +101 -0
  35. data/lib/chef/rest.rb +4 -5
  36. data/lib/chef/search/query.rb +1 -1
  37. data/lib/chef/server_api.rb +1 -0
  38. data/lib/chef/version.rb +1 -1
  39. data/spec/data/lwrp/providers/buck_passer.rb +2 -1
  40. data/spec/data/lwrp/resources/bar.rb +1 -1
  41. data/spec/data/{big_json.json → nested.json} +2 -2
  42. data/spec/functional/event_loggers/windows_eventlog_spec.rb +14 -0
  43. data/spec/functional/resource/execute_spec.rb +1 -1
  44. data/spec/integration/client/client_spec.rb +12 -1
  45. data/spec/integration/client/ipv6_spec.rb +1 -1
  46. data/spec/integration/knife/common_options_spec.rb +3 -3
  47. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +1 -1
  48. data/spec/integration/solo/solo_spec.rb +7 -5
  49. data/spec/unit/application/client_spec.rb +10 -0
  50. data/spec/unit/chef_class_spec.rb +91 -0
  51. data/spec/unit/client_spec.rb +13 -0
  52. data/spec/unit/http/basic_client_spec.rb +43 -6
  53. data/spec/unit/http/socketless_chef_zero_client_spec.rb +174 -0
  54. data/spec/unit/http_spec.rb +14 -0
  55. data/spec/unit/json_compat_spec.rb +7 -20
  56. data/spec/unit/knife/ssh_spec.rb +18 -0
  57. data/spec/unit/knife/status_spec.rb +69 -3
  58. data/spec/unit/knife_spec.rb +5 -0
  59. data/spec/unit/provider/package/rubygems_spec.rb +19 -0
  60. data/spec/unit/provider/service/macosx_spec.rb +230 -203
  61. data/spec/unit/provider_resolver_spec.rb +1 -0
  62. data/spec/unit/recipe_spec.rb +48 -0
  63. data/spec/unit/resource/link_spec.rb +15 -0
  64. data/spec/unit/resource_spec.rb +6 -6
  65. data/spec/unit/rest_spec.rb +9 -0
  66. data/spec/unit/search/query_spec.rb +24 -0
  67. data/spec/unit/shell_spec.rb +3 -1
  68. metadata +16 -9
  69. data/spec/data/big_json_plus_one.json +0 -2
@@ -20,6 +20,7 @@ require 'spec_helper'
20
20
 
21
21
  require 'chef/http'
22
22
  require 'chef/http/basic_client'
23
+ require 'chef/http/socketless_chef_zero_client'
23
24
 
24
25
  class Chef::HTTP
25
26
  public :create_url
@@ -27,6 +28,19 @@ end
27
28
 
28
29
  describe Chef::HTTP do
29
30
 
31
+ context "when given a chefzero:// URL" do
32
+
33
+ let(:uri) { URI("chefzero://localhost:1") }
34
+
35
+ subject(:http) { Chef::HTTP.new(uri) }
36
+
37
+ it "uses the SocketlessChefZeroClient to handle requests" do
38
+ expect(http.http_client).to be_a_kind_of(Chef::HTTP::SocketlessChefZeroClient)
39
+ expect(http.http_client.url).to eq(uri)
40
+ end
41
+
42
+ end
43
+
30
44
  describe "create_url" do
31
45
 
32
46
  it 'should return a correctly formatted url 1/3 CHEF-5261' do
@@ -72,32 +72,19 @@ describe Chef::JSONCompat do
72
72
  end
73
73
  end
74
74
 
75
- describe "with a file with 300 or less nested entries" do
76
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json.json')) }
75
+ # On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
76
+ # https://github.com/chef/chef/issues/3101
77
+ describe "with the file with 252 or less nested entries" do
78
+ let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
77
79
  let(:hash) { Chef::JSONCompat.from_json(json) }
78
80
 
79
- describe "when a big json file is loaded" do
81
+ describe "when the 252 json file is loaded" do
80
82
  it "should create a Hash from the file" do
81
83
  expect(hash).to be_kind_of(Hash)
82
84
  end
83
85
 
84
- it "should has 'test' as a 300th nested value" do
85
- expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
86
- end
87
- end
88
- end
89
-
90
- describe "with a file with more than 300 nested entries" do
91
- let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'big_json_plus_one.json')) }
92
- let(:hash) { Chef::JSONCompat.from_json(json, {:max_nesting => 301}) }
93
-
94
- describe "when a big json file is loaded" do
95
- it "should create a Hash from the file" do
96
- expect(hash).to be_kind_of(Hash)
97
- end
98
-
99
- it "should has 'test' as a 301st nested value" do
100
- expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
86
+ it "should has 'test' as a 252 nested value" do
87
+ expect(hash['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']['key']).to eq('test')
101
88
  end
102
89
  end
103
90
  end
@@ -96,6 +96,24 @@ describe Chef::Knife::Ssh do
96
96
  should_return_specified_attributes
97
97
  end
98
98
 
99
+ context "when cloud hostnames are available but empty" do
100
+ before do
101
+ @node_foo.automatic_attrs[:cloud][:public_hostname] = ''
102
+ @node_bar.automatic_attrs[:cloud][:public_hostname] = ''
103
+ end
104
+
105
+ it "returns an array of fqdns" do
106
+ configure_query([@node_foo, @node_bar])
107
+ expect(@knife).to receive(:session_from_list).with([
108
+ ['foo.example.org', nil],
109
+ ['bar.example.org', nil]
110
+ ])
111
+ @knife.configure_session
112
+ end
113
+
114
+ should_return_specified_attributes
115
+ end
116
+
99
117
  it "should raise an error if no host are found" do
100
118
  configure_query([ ])
101
119
  expect(@knife.ui).to receive(:fatal)
@@ -24,15 +24,81 @@ describe Chef::Knife::Status do
24
24
  n.automatic_attrs["fqdn"] = "foobar"
25
25
  n.automatic_attrs["ohai_time"] = 1343845969
26
26
  end
27
- query = double("Chef::Search::Query")
28
- allow(query).to receive(:search).and_yield(node)
29
- allow(Chef::Search::Query).to receive(:new).and_return(query)
27
+ allow(Time).to receive(:now).and_return(Time.at(1428573420))
28
+ @query = double("Chef::Search::Query")
29
+ allow(@query).to receive(:search).and_yield(node)
30
+ allow(Chef::Search::Query).to receive(:new).and_return(@query)
30
31
  @knife = Chef::Knife::Status.new
31
32
  @stdout = StringIO.new
32
33
  allow(@knife.ui).to receive(:stdout).and_return(@stdout)
33
34
  end
34
35
 
35
36
  describe "run" do
37
+ let(:opts) {{filter_result:
38
+ { name: ["name"], ipaddress: ["ipaddress"], ohai_time: ["ohai_time"],
39
+ ec2: ["ec2"], run_list: ["run_list"], platform: ["platform"],
40
+ platform_version: ["platform_version"], chef_environment: ["chef_environment"]}}}
41
+
42
+ it "should default to searching for everything" do
43
+ expect(@query).to receive(:search).with(:node, "*:*", opts)
44
+ @knife.run
45
+ end
46
+
47
+ it "should filter healthy nodes" do
48
+ @knife.config[:hide_healthy] = true
49
+ expect(@query).to receive(:search).with(:node, "NOT ohai_time:[1428569820 TO 1428573420]", opts)
50
+ @knife.run
51
+ end
52
+
53
+ it "should filter by environment" do
54
+ @knife.config[:environment] = "production"
55
+ expect(@query).to receive(:search).with(:node, "chef_environment:production", opts)
56
+ @knife.run
57
+ end
58
+
59
+ it "should filter by environment and health" do
60
+ @knife.config[:environment] = "production"
61
+ @knife.config[:hide_healthy] = true
62
+ expect(@query).to receive(:search).with(:node, "chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
63
+ @knife.run
64
+ end
65
+
66
+ it "should not use partial search with long output" do
67
+ @knife.config[:long_output] = true
68
+ expect(@query).to receive(:search).with(:node, "*:*", {})
69
+ @knife.run
70
+ end
71
+
72
+ context "with a custom query" do
73
+ before :each do
74
+ @knife.instance_variable_set(:@name_args, ["name:my_custom_name"])
75
+ end
76
+
77
+ it "should allow a custom query to be specified" do
78
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name", opts)
79
+ @knife.run
80
+ end
81
+
82
+ it "should filter healthy nodes" do
83
+ @knife.config[:hide_healthy] = true
84
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name NOT ohai_time:[1428569820 TO 1428573420]", opts)
85
+ @knife.run
86
+ end
87
+
88
+ it "should filter by environment" do
89
+ @knife.config[:environment] = "production"
90
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production", opts)
91
+ @knife.run
92
+ end
93
+
94
+ it "should filter by environment and health" do
95
+ @knife.config[:environment] = "production"
96
+ @knife.config[:hide_healthy] = true
97
+ expect(@query).to receive(:search).with(:node, "name:my_custom_name AND chef_environment:production NOT ohai_time:[1428569820 TO 1428573420]", opts)
98
+ @knife.run
99
+ end
100
+ end
101
+
36
102
  it "should not colorize output unless it's writing to a tty" do
37
103
  @knife.run
38
104
  expect(@stdout.string.match(/foobar/)).not_to be_nil
@@ -271,6 +271,11 @@ describe Chef::Knife do
271
271
  expect(knife_command.config[:opt_with_default]).to eq("from-cli")
272
272
  end
273
273
 
274
+ it "merges `listen` config to Chef::Config" do
275
+ Chef::Knife.run(%w[test yourself --no-listen], Chef::Application::Knife.options)
276
+ expect(Chef::Config[:listen]).to be(false)
277
+ end
278
+
274
279
  context "verbosity is greater than zero" do
275
280
  let(:fake_config) { "/does/not/exist/knife.rb" }
276
281
 
@@ -547,6 +547,25 @@ describe Chef::Provider::Package::Rubygems do
547
547
  expect(@new_resource).to be_updated_by_last_action
548
548
  end
549
549
 
550
+ it "installs the gem with rubygems.org as an added source" do
551
+ @new_resource.gem_binary('/foo/bar')
552
+ @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
553
+ expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --source=#{@new_resource.source} --source=https://rubygems.org"
554
+ expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
555
+ @provider.run_action(:install)
556
+ expect(@new_resource).to be_updated_by_last_action
557
+ end
558
+
559
+ it "installs the gem with cleared sources and explict source when specified" do
560
+ @new_resource.gem_binary('/foo/bar')
561
+ @new_resource.source('http://mirror.ops.rhcloud.com/mirror/ruby')
562
+ @new_resource.clear_sources(true)
563
+ expected ="/foo/bar install rspec-core -q --no-rdoc --no-ri -v \"#{@spec_version}\" --clear-sources --source=#{@new_resource.source}"
564
+ expect(@provider).to receive(:shell_out!).with(expected, :env => nil)
565
+ @provider.run_action(:install)
566
+ expect(@new_resource).to be_updated_by_last_action
567
+ end
568
+
550
569
  context "when no version is given" do
551
570
  let(:target_version) { nil }
552
571
 
@@ -58,248 +58,275 @@ describe Chef::Provider::Service::Macosx do
58
58
  </plist>
59
59
  XML
60
60
 
61
- ["redis-server", "io.redis.redis-server"].each do |service_name|
62
- before do
63
- allow(Dir).to receive(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], [])
64
- allow(provider).to receive(:shell_out!).
65
- with("launchctl list", {:group => 1001, :user => 101}).
66
- and_return(double("Status", :stdout => launchctl_stdout))
67
- allow(provider).to receive(:shell_out).
68
- with(/launchctl list /,
69
- {:group => nil, :user => nil}).
70
- and_return(double("Status",
71
- :stdout => launchctl_stdout, :exitstatus => 0))
72
- allow(provider).to receive(:shell_out!).
73
- with(/plutil -convert xml1 -o/).
74
- and_return(double("Status", :stdout => plutil_stdout))
75
-
76
- allow(File).to receive(:stat).and_return(double("stat", :gid => 1001, :uid => 101))
77
- end
78
-
79
- context "#{service_name}" do
80
- let(:new_resource) { Chef::Resource::Service.new(service_name) }
81
- let!(:current_resource) { Chef::Resource::Service.new(service_name) }
82
-
83
- describe "#load_current_resource" do
84
-
85
- # CHEF-5223 "you can't glob for a file that hasn't been converged
86
- # onto the node yet."
87
- context "when the plist doesn't exist" do
88
-
89
- def run_resource_setup_for_action(action)
90
- new_resource.action(action)
91
- provider.action = action
92
- provider.load_current_resource
93
- provider.define_resource_requirements
94
- provider.process_resource_requirements
95
- end
96
-
97
- before do
98
- allow(Dir).to receive(:glob).and_return([])
99
- allow(provider).to receive(:shell_out!).
100
- with(/plutil -convert xml1 -o/).
101
- and_raise(Mixlib::ShellOut::ShellCommandFailed)
102
- end
103
-
104
- it "works for action :nothing" do
105
- expect { run_resource_setup_for_action(:nothing) }.not_to raise_error
106
- end
107
-
108
- it "works for action :start" do
109
- expect { run_resource_setup_for_action(:start) }.not_to raise_error
110
- end
111
-
112
- it "errors if action is :enable" do
113
- expect { run_resource_setup_for_action(:enable) }.to raise_error(Chef::Exceptions::Service)
114
- end
115
-
116
- it "errors if action is :disable" do
117
- expect { run_resource_setup_for_action(:disable) }.to raise_error(Chef::Exceptions::Service)
61
+ ["Daemon", "Agent"].each do |service_type|
62
+ ["redis-server", "io.redis.redis-server"].each do |service_name|
63
+ ["10.9", "10.10"].each do |platform_version|
64
+ let(:plist) {'/Library/LaunchDaemons/io.redis.redis-server.plist'}
65
+ let(:session) { StringIO.new }
66
+ if service_type == 'Agent'
67
+ let(:plist) {'/Library/LaunchAgents/io.redis.redis-server.plist'}
68
+ let(:session) {'-S Aqua '}
69
+ let(:su_cmd) {'su igor -c'}
70
+ if platform_version != "10.10"
71
+ let(:su_cmd) {'su -l igor -c'}
118
72
  end
119
73
  end
120
-
121
- context "when launchctl returns pid in service list" do
122
- let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
123
- 12761 - 0x100114220.old.machinit.thing
124
- 7777 - io.redis.redis-server
125
- - - com.lol.stopped-thing
126
- SVC_LIST
127
-
128
- before do
129
- provider.load_current_resource
130
- end
131
-
132
- it "sets resource running state to true" do
133
- expect(provider.current_resource.running).to be_truthy
134
- end
135
-
136
- it "sets resouce enabled state to true" do
137
- expect(provider.current_resource.enabled).to be_truthy
138
- end
74
+ let(:service_label) {'io.redis.redis-server'}
75
+ before do
76
+ allow(Dir).to receive(:glob).and_return([plist], [])
77
+ allow(Etc).to receive(:getlogin).and_return('igor')
78
+ allow(node).to receive(:[]).with("platform_version").and_return(platform_version)
79
+ cmd = "launchctl list #{service_label}"
80
+ allow(provider).to receive(:shell_out_with_systems_locale).
81
+ with(/(#{su_cmd} '#{cmd}'|#{cmd})/).
82
+ and_return(double("Status",
83
+ :stdout => launchctl_stdout, :exitstatus => 0))
84
+ allow(File).to receive(:exists?).and_return([true], [])
85
+ allow(provider).to receive(:shell_out_with_systems_locale!).
86
+ with(/plutil -convert xml1 -o/).
87
+ and_return(double("Status", :stdout => plutil_stdout))
139
88
  end
140
89
 
141
- describe "running unsupported actions" do
142
- let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
143
- 12761 - 0x100114220.old.machinit.thing
144
- 7777 - io.redis.redis-server
145
- - - com.lol.stopped-thing
90
+ context "#{service_name} that is a #{service_type} running Osx #{platform_version}" do
91
+ let(:new_resource) { Chef::Resource::MacosxService.new(service_name) }
92
+ let!(:current_resource) { Chef::Resource::MacosxService.new(service_name) }
93
+
94
+ describe "#load_current_resource" do
95
+
96
+ # CHEF-5223 "you can't glob for a file that hasn't been converged
97
+ # onto the node yet."
98
+ context "when the plist doesn't exist" do
99
+
100
+ def run_resource_setup_for_action(action)
101
+ new_resource.action(action)
102
+ provider.action = action
103
+ provider.load_current_resource
104
+ provider.define_resource_requirements
105
+ provider.process_resource_requirements
106
+ end
107
+
108
+ before do
109
+ allow(Dir).to receive(:glob).and_return([])
110
+ allow(File).to receive(:exists?).and_return([true], [])
111
+ allow(provider).to receive(:shell_out!).
112
+ with(/plutil -convert xml1 -o/).
113
+ and_raise(Mixlib::ShellOut::ShellCommandFailed)
114
+ end
115
+
116
+ it "works for action :nothing" do
117
+ expect { run_resource_setup_for_action(:nothing) }.not_to raise_error
118
+ end
119
+
120
+ it "works for action :start" do
121
+ expect { run_resource_setup_for_action(:start) }.not_to raise_error
122
+ end
123
+
124
+ it "errors if action is :enable" do
125
+ expect { run_resource_setup_for_action(:enable) }.to raise_error(Chef::Exceptions::Service)
126
+ end
127
+
128
+ it "errors if action is :disable" do
129
+ expect { run_resource_setup_for_action(:disable) }.to raise_error(Chef::Exceptions::Service)
130
+ end
131
+ end
132
+
133
+ context "when launchctl returns pid in service list" do
134
+ let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
135
+ {
136
+ "LimitLoadToSessionType" = "System";
137
+ "Label" = "io.redis.redis-server";
138
+ "TimeOut" = 30;
139
+ "OnDemand" = false;
140
+ "LastExitStatus" = 0;
141
+ "PID" = 62803;
142
+ "Program" = "do_some.sh";
143
+ "ProgramArguments" = (
144
+ "path/to/do_something.sh";
145
+ "-f";
146
+ );
147
+ };
146
148
  SVC_LIST
147
149
 
148
- before do
149
- allow(Dir).to receive(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], [])
150
- end
151
- it "should throw an exception when reload action is attempted" do
152
- expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
153
- end
154
- end
155
- context "when launchctl returns empty service pid" do
156
- let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
157
- 12761 - 0x100114220.old.machinit.thing
158
- - - io.redis.redis-server
159
- - - com.lol.stopped-thing
160
- SVC_LIST
161
-
162
- before do
163
- provider.load_current_resource
164
- end
150
+ before do
151
+ provider.load_current_resource
152
+ end
165
153
 
166
- it "sets resource running state to false" do
167
- expect(provider.current_resource.running).to be_falsey
168
- end
154
+ it "sets resource running state to true" do
155
+ expect(provider.current_resource.running).to be_truthy
156
+ end
169
157
 
170
- it "sets resouce enabled state to true" do
171
- expect(provider.current_resource.enabled).to be_truthy
172
- end
173
- end
158
+ it "sets resouce enabled state to true" do
159
+ expect(provider.current_resource.enabled).to be_truthy
160
+ end
161
+ end
174
162
 
175
- context "when launchctl doesn't return service entry at all" do
176
- let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
177
- 12761 - 0x100114220.old.machinit.thing
178
- - - com.lol.stopped-thing
179
- SVC_LIST
163
+ describe "running unsupported actions" do
164
+ before do
165
+ allow(Dir).to receive(:glob).and_return(["#{plist}"], [])
166
+ allow(File).to receive(:exists?).and_return([true], [])
167
+ end
168
+ it "should throw an exception when reload action is attempted" do
169
+ expect {provider.run_action(:reload)}.to raise_error(Chef::Exceptions::UnsupportedAction)
170
+ end
171
+ end
172
+ context "when launchctl returns empty service pid" do
173
+ let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
174
+ {
175
+ "LimitLoadToSessionType" = "System";
176
+ "Label" = "io.redis.redis-server";
177
+ "TimeOut" = 30;
178
+ "OnDemand" = false;
179
+ "LastExitStatus" = 0;
180
+ "Program" = "do_some.sh";
181
+ "ProgramArguments" = (
182
+ "path/to/do_something.sh";
183
+ "-f";
184
+ );
185
+ };
186
+ SVC_LIST
180
187
 
181
- it "sets service running state to false" do
182
- provider.load_current_resource
183
- expect(provider.current_resource.running).to be_falsey
184
- end
188
+ before do
189
+ provider.load_current_resource
190
+ end
185
191
 
186
- context "and plist for service is not available" do
187
- before do
188
- allow(Dir).to receive(:glob).and_return([])
189
- provider.load_current_resource
190
- end
192
+ it "sets resource running state to false" do
193
+ expect(provider.current_resource.running).to be_falsey
194
+ end
191
195
 
192
- it "sets resouce enabled state to false" do
193
- expect(provider.current_resource.enabled).to be_falsey
196
+ it "sets resouce enabled state to true" do
197
+ expect(provider.current_resource.enabled).to be_truthy
198
+ end
194
199
  end
195
- end
196
200
 
197
- context "and plist for service is available" do
198
- before do
199
- allow(Dir).to receive(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist"], [])
200
- provider.load_current_resource
201
- end
201
+ context "when launchctl doesn't return service entry at all" do
202
+ let(:launchctl_stdout) { StringIO.new <<-SVC_LIST }
203
+ Could not find service "io.redis.redis-server" in domain for system
204
+ SVC_LIST
202
205
 
203
- it "sets resouce enabled state to true" do
204
- expect(provider.current_resource.enabled).to be_truthy
206
+ it "sets service running state to false" do
207
+ provider.load_current_resource
208
+ expect(provider.current_resource.running).to be_falsey
209
+ end
210
+
211
+ context "and plist for service is not available" do
212
+ before do
213
+ allow(Dir).to receive(:glob).and_return([])
214
+ provider.load_current_resource
215
+ end
216
+
217
+ it "sets resouce enabled state to false" do
218
+ expect(provider.current_resource.enabled).to be_falsey
219
+ end
220
+ end
221
+
222
+ context "and plist for service is available" do
223
+ before do
224
+ allow(Dir).to receive(:glob).and_return(["#{plist}"], [])
225
+ provider.load_current_resource
226
+ end
227
+
228
+ it "sets resouce enabled state to true" do
229
+ expect(provider.current_resource.enabled).to be_truthy
230
+ end
231
+ end
232
+
233
+ describe "and several plists match service name" do
234
+ it "throws exception" do
235
+ allow(Dir).to receive(:glob).and_return(["#{plist}",
236
+ "/Users/wtf/something.plist"])
237
+ provider.load_current_resource
238
+ provider.define_resource_requirements
239
+ expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
240
+ end
241
+ end
205
242
  end
206
243
  end
207
-
208
- describe "and several plists match service name" do
209
- it "throws exception" do
210
- allow(Dir).to receive(:glob).and_return(["/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist",
211
- "/Users/wtf/something.plist"])
244
+ describe "#start_service" do
245
+ before do
246
+ allow(Chef::Resource::MacosxService).to receive(:new).and_return(current_resource)
212
247
  provider.load_current_resource
213
- provider.define_resource_requirements
214
- expect { provider.process_resource_requirements }.to raise_error(Chef::Exceptions::Service)
248
+ allow(current_resource).to receive(:running).and_return(false)
215
249
  end
216
- end
217
- end
218
- end
219
- describe "#start_service" do
220
- before do
221
- allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
222
- provider.load_current_resource
223
- allow(current_resource).to receive(:running).and_return(false)
224
- end
225
250
 
226
- it "calls the start command if one is specified and service is not running" do
227
- allow(new_resource).to receive(:start_command).and_return("cowsay dirty")
251
+ it "calls the start command if one is specified and service is not running" do
252
+ allow(new_resource).to receive(:start_command).and_return("cowsay dirty")
228
253
 
229
- expect(provider).to receive(:shell_out_with_systems_locale!).with("cowsay dirty")
230
- provider.start_service
231
- end
254
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("cowsay dirty")
255
+ provider.start_service
256
+ end
232
257
 
233
- it "shows warning message if service is already running" do
234
- allow(current_resource).to receive(:running).and_return(true)
235
- expect(Chef::Log).to receive(:debug).with("service[#{service_name}] already running, not starting")
258
+ it "shows warning message if service is already running" do
259
+ allow(current_resource).to receive(:running).and_return(true)
260
+ expect(Chef::Log).to receive(:debug).with("macosx_service[#{service_name}] already running, not starting")
236
261
 
237
- provider.start_service
238
- end
262
+ provider.start_service
263
+ end
239
264
 
240
- it "starts service via launchctl if service found" do
241
- expect(provider).to receive(:shell_out_with_systems_locale!).
242
- with("launchctl load -w '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'",
243
- :group => 1001, :user => 101).
244
- and_return(0)
265
+ it "starts service via launchctl if service found" do
266
+ cmd = 'launchctl load -w ' + session + plist
267
+ expect(provider).to receive(:shell_out_with_systems_locale).
268
+ with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
269
+ and_return(0)
245
270
 
246
- provider.start_service
247
- end
248
- end
271
+ provider.start_service
272
+ end
273
+ end
249
274
 
250
- describe "#stop_service" do
251
- before do
252
- allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
275
+ describe "#stop_service" do
276
+ before do
277
+ allow(Chef::Resource::MacosxService).to receive(:new).and_return(current_resource)
253
278
 
254
- provider.load_current_resource
255
- allow(current_resource).to receive(:running).and_return(true)
256
- end
279
+ provider.load_current_resource
280
+ allow(current_resource).to receive(:running).and_return(true)
281
+ end
257
282
 
258
- it "calls the stop command if one is specified and service is running" do
259
- allow(new_resource).to receive(:stop_command).and_return("kill -9 123")
283
+ it "calls the stop command if one is specified and service is running" do
284
+ allow(new_resource).to receive(:stop_command).and_return("kill -9 123")
260
285
 
261
- expect(provider).to receive(:shell_out_with_systems_locale!).with("kill -9 123")
262
- provider.stop_service
263
- end
286
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("kill -9 123")
287
+ provider.stop_service
288
+ end
264
289
 
265
- it "shows warning message if service is not running" do
266
- allow(current_resource).to receive(:running).and_return(false)
267
- expect(Chef::Log).to receive(:debug).with("service[#{service_name}] not running, not stopping")
290
+ it "shows warning message if service is not running" do
291
+ allow(current_resource).to receive(:running).and_return(false)
292
+ expect(Chef::Log).to receive(:debug).with("macosx_service[#{service_name}] not running, not stopping")
268
293
 
269
- provider.stop_service
270
- end
294
+ provider.stop_service
295
+ end
271
296
 
272
- it "stops the service via launchctl if service found" do
273
- expect(provider).to receive(:shell_out_with_systems_locale!).
274
- with("launchctl unload '/Users/igor/Library/LaunchAgents/io.redis.redis-server.plist'",
275
- :group => 1001, :user => 101).
276
- and_return(0)
297
+ it "stops the service via launchctl if service found" do
298
+ cmd = 'launchctl unload -w '+ plist
299
+ expect(provider).to receive(:shell_out_with_systems_locale).
300
+ with(/(#{su_cmd} .#{cmd}.|#{cmd})/).
301
+ and_return(0)
277
302
 
278
- provider.stop_service
279
- end
280
- end
303
+ provider.stop_service
304
+ end
305
+ end
281
306
 
282
- describe "#restart_service" do
283
- before do
284
- allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
307
+ describe "#restart_service" do
308
+ before do
309
+ allow(Chef::Resource::Service).to receive(:new).and_return(current_resource)
285
310
 
286
- provider.load_current_resource
287
- allow(current_resource).to receive(:running).and_return(true)
288
- allow(provider).to receive(:sleep)
289
- end
311
+ provider.load_current_resource
312
+ allow(current_resource).to receive(:running).and_return(true)
313
+ allow(provider).to receive(:sleep)
314
+ end
290
315
 
291
- it "issues a command if given" do
292
- allow(new_resource).to receive(:restart_command).and_return("reload that thing")
316
+ it "issues a command if given" do
317
+ allow(new_resource).to receive(:restart_command).and_return("reload that thing")
293
318
 
294
- expect(provider).to receive(:shell_out_with_systems_locale!).with("reload that thing")
295
- provider.restart_service
296
- end
319
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("reload that thing")
320
+ provider.restart_service
321
+ end
297
322
 
298
- it "stops and then starts service" do
299
- expect(provider).to receive(:stop_service)
300
- expect(provider).to receive(:start_service);
323
+ it "stops and then starts service" do
324
+ expect(provider).to receive(:unload_service)
325
+ expect(provider).to receive(:load_service);
301
326
 
302
- provider.restart_service
327
+ provider.restart_service
328
+ end
329
+ end
303
330
  end
304
331
  end
305
332
  end