summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Barnett <jason.w.barnett@gmail.com>2018-01-25 09:15:09 -0500
committerJason Barnett <jason.w.barnett@gmail.com>2018-01-26 14:30:03 -0800
commitd4c645016baf361f823b5d8c940ff6ff750ac6a3 (patch)
treea636d75fe98adc4197c056cc49eb16789508e2d0
parent97b6d1a78f957d605e5cb840d3516cf7705a44c4 (diff)
downloadchef-d4c645016baf361f823b5d8c940ff6ff750ac6a3.tar.gz
Fix existing tests and add new ones
Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as Indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. Signed-off-by: Jason Barnett <jason.w.barnett@gmail.com>
-rw-r--r--lib/chef/provider/service/windows.rb152
-rw-r--r--lib/chef/resource/windows_service.rb38
-rw-r--r--spec/unit/provider/service/windows_spec.rb453
-rw-r--r--spec/unit/resource/windows_service_spec.rb25
4 files changed, 561 insertions, 107 deletions
diff --git a/lib/chef/provider/service/windows.rb b/lib/chef/provider/service/windows.rb
index b104edc3fd..603b9f7985 100644
--- a/lib/chef/provider/service/windows.rb
+++ b/lib/chef/provider/service/windows.rb
@@ -58,27 +58,24 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
if Win32::Service.exists?(current_resource.service_name)
current_resource.running(current_state == RUNNING)
Chef::Log.debug "#{new_resource} running: #{current_resource.running}"
- case current_start_type
- when AUTO_START
+ case current_startup_type
+ when :automatic
current_resource.enabled(true)
- when DISABLED
+ when :disabled
current_resource.enabled(false)
end
Chef::Log.debug "#{new_resource} enabled: #{current_resource.enabled}"
config_info = Win32::Service.config_info(current_resource.service_name)
- current_resource.service_type(get_service_type(config_info[:service_type])) if config_info[:service_type]
- current_resource.startup_type(get_start_type(config_info[:start_type])) if config_info[:start_type]
- current_resource.error_control(get_error_control(config_info[:error_control])) if config_info[:error_control]
- current_resource.binary_path_name(config_info[:binary_path_name]) if config_info[:binary_path_name]
- current_resource.load_order_group(config_info[:load_order_group]) if config_info[:load_order_group]
- current_resource.dependencies(config_info[:dependencies]) if config_info[:dependencies]
- current_resource.run_as_user(config_info[:service_start_name]) if config_info[:service_start_name]
- current_resource.display_name(config_info[:display_name]) if config_info[:display_name]
-
- if delayed_start = current_delayed_start
- current_resource.delayed_start(delayed_start)
- end
+ current_resource.service_type(get_service_type(config_info.service_type)) if config_info.service_type
+ current_resource.startup_type(start_type_to_sym(config_info.start_type)) if config_info.start_type
+ current_resource.error_control(get_error_control(config_info.error_control)) if config_info.error_control
+ current_resource.binary_path_name(config_info.binary_path_name) if config_info.binary_path_name
+ current_resource.load_order_group(config_info.load_order_group) if config_info.load_order_group
+ current_resource.dependencies(config_info.dependencies) if config_info.dependencies
+ current_resource.run_as_user(config_info.service_start_name) if config_info.service_start_name
+ current_resource.display_name(config_info.display_name) if config_info.display_name
+ current_resource.delayed_start(current_delayed_start) if current_delayed_start
end
current_resource
@@ -196,7 +193,10 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
action :create do
- return if Win32::Service.exists?(new_resource.service_name)
+ if Win32::Service.exists?(new_resource.service_name)
+ Chef::Log.debug "#{new_resource} already exists - nothing to do"
+ return
+ end
converge_by("create service #{new_resource.service_name}") do
Win32::Service.new(windows_service_config)
@@ -206,7 +206,10 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
action :delete do
- return unless Win32::Service.exists?(new_resource.service_name)
+ unless Win32::Service.exists?(new_resource.service_name)
+ Chef::Log.debug "#{new_resource} does not exist - nothing to do"
+ return
+ end
converge_by("delete service #{new_resource.service_name}") do
Win32::Service.delete(new_resource.service_name)
@@ -215,7 +218,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
action :configure do
unless Win32::Service.exists?(new_resource.service_name)
- Chef::Log.debug "#{new_resource} does not exist - nothing to do"
+ Chef::Log.warn "#{new_resource} does not exist. Maybe you need to prepend action :create"
return
end
@@ -234,7 +237,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
def action_enable
- if current_start_type != AUTO_START
+ if current_startup_type != :automatic
converge_by("enable service #{@new_resource}") do
enable_service
Chef::Log.info("#{@new_resource} enabled")
@@ -247,7 +250,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
def action_disable
- if current_start_type != DISABLED
+ if current_startup_type != :disabled
converge_by("disable service #{@new_resource}") do
disable_service
Chef::Log.info("#{@new_resource} disabled")
@@ -260,31 +263,13 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
def action_configure_startup
- case @new_resource.startup_type
- when :automatic
- if current_start_type != AUTO_START
- converge_by("set service #{@new_resource} startup type to automatic") do
- set_startup_type(:automatic)
- end
- else
- Chef::Log.debug("#{@new_resource} startup_type already automatic - nothing to do")
- end
- when :manual
- if current_start_type != MANUAL
- converge_by("set service #{@new_resource} startup type to manual") do
- set_startup_type(:manual)
- end
- else
- Chef::Log.debug("#{@new_resource} startup_type already manual - nothing to do")
- end
- when :disabled
- if current_start_type != DISABLED
- converge_by("set service #{@new_resource} startup type to disabled") do
- set_startup_type(:disabled)
- end
- else
- Chef::Log.debug("#{@new_resource} startup_type already disabled - nothing to do")
+ startup_type = @new_resource.startup_type
+ if current_startup_type != startup_type
+ converge_by("set service #{@new_resource} startup type to #{startup_type}") do
+ set_startup_type(startup_type)
end
+ else
+ Chef::Log.debug("#{@new_resource} startup_type already #{startup_type} - nothing to do")
end
# Avoid changing enabled from true/false for now
@@ -294,8 +279,8 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
private
def current_delayed_start
- if service = Win32::Service.services.find { |x| x.service_name == @new_resource.service_name }
- service.delayed_start
+ if service = Win32::Service.services.find { |x| x.service_name == new_resource.service_name }
+ service.delayed_start.zero? ? false : true
else
nil
end
@@ -326,8 +311,9 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
Win32::Service.status(@new_resource.service_name).current_state
end
- def current_start_type
- Win32::Service.config_info(@new_resource.service_name).start_type
+ def current_startup_type
+ start_type = Win32::Service.config_info(@new_resource.service_name).start_type
+ start_type_to_sym(start_type)
end
# Helper method that waits for a status to change its state since state
@@ -355,20 +341,25 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
end
- # Takes Win32::Service start_types
- def set_startup_type(type)
- # Set-Service Startup Type => Win32::Service Constant
- allowed_types = { :automatic => Win32::Service::AUTO_START,
- :manual => Win32::Service::DEMAND_START,
- :disabled => Win32::Service::DISABLED }
- unless allowed_types.keys.include?(type)
+ # @param type [Symbol]
+ # @return [Integer]
+ # @raise [Chef::Exceptions::ConfigurationError] if the startup type is
+ # not supported.
+ # @see Chef::Resource::WindowsService::ALLOWED_START_TYPES
+ def startup_type_to_int(type)
+ Chef::Resource::WindowsService::ALLOWED_START_TYPES.fetch(type) do
raise Chef::Exceptions::ConfigurationError, "#{@new_resource.name}: Startup type '#{type}' is not supported"
end
+ end
+
+ # Takes Win32::Service start_types
+ def set_startup_type(type)
+ startup_type = startup_type_to_int(type)
Chef::Log.debug "#{@new_resource.name} setting start_type to #{type}"
Win32::Service.configure(
:service_name => @new_resource.service_name,
- :start_type => allowed_types[type]
+ :start_type => startup_type
)
@new_resource.updated_by_last_action(true)
end
@@ -377,20 +368,20 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
config = {}
config[:service_name] = new_resource.service_name
- config[:display_name] = new_resource.display_name if new_resource.display_name
- config[:service_type] = new_resource.service_type if new_resource.service_type
- config[:start_type] = new_resource.startup_type if new_resource.startup_type
- config[:error_control] = new_resource.error_control if new_resource.error_control
- config[:binary_path_name] = new_resource.binary_path_name if new_resource.binary_path_name
- config[:load_order_group] = new_resource.load_order_group if new_resource.load_order_group
- config[:dependencies] = new_resource.dependencies if new_resource.dependencies
- config[:service_start_name] = new_resource.run_as_user unless new_resource.run_as_user.empty?
- config[:password] = new_resource.run_as_password unless new_resource.run_as_user.empty? or new_resource.run_as_password.empty?
- config[:description] = new_resource.description if new_resource.description
+ config[:display_name] = new_resource.display_name if new_resource.display_name
+ config[:service_type] = new_resource.service_type if new_resource.service_type
+ config[:start_type] = startup_type_to_int(new_resource.startup_type) if new_resource.startup_type
+ config[:error_control] = new_resource.error_control if new_resource.error_control
+ config[:binary_path_name] = new_resource.binary_path_name if new_resource.binary_path_name
+ config[:load_order_group] = new_resource.load_order_group if new_resource.load_order_group
+ config[:dependencies] = new_resource.dependencies if new_resource.dependencies
+ config[:service_start_name] = new_resource.run_as_user unless new_resource.run_as_user.empty?
+ config[:password] = new_resource.run_as_password unless new_resource.run_as_user.empty? or new_resource.run_as_password.empty?
+ config[:description] = new_resource.description if new_resource.description
case action
when :create
- config[:desired_access] = new_resource.desired_access if new_resource.desired_access
+ config[:desired_access] = new_resource.desired_access if new_resource.desired_access
end
config
@@ -399,7 +390,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
def converge_delayed_start
config = {}
config[:service_name] = new_resource.service_name
- config[:delayed_start] = new_resource.delayed_start
+ config[:delayed_start] = new_resource.delayed_start ? 1 : 0
# Until #6300 is solved this is required
if new_resource.delayed_start == new_resource.class.properties[:delayed_start].default
@@ -411,6 +402,24 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
end
end
+ # @return [Symbol]
+ def start_type_to_sym(start_type)
+ case start_type
+ when 'auto start'
+ :automatic
+ when 'boot start'
+ raise("Unsupported start type, #{start_type}. Submit bug request to fix.")
+ when 'demand start'
+ :manual
+ when 'disabled'
+ :disabled
+ when 'system start'
+ raise("Unsupported start type, #{start_type}. Submit bug request to fix.")
+ else
+ raise("Unsupported start type, #{start_type}. Submit bug request to fix.")
+ end
+ end
+
def get_service_type(service_type)
case service_type
when 'file system driver'
@@ -419,7 +428,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
SERVICE_KERNEL_DRIVER
when 'own process'
SERVICE_WIN32_OWN_PROCESS
- when 'share proces'
+ when 'share process'
SERVICE_WIN32_SHARE_PROCESS
when 'recognizer driver'
SERVICE_RECOGNIZER_DRIVER
@@ -434,10 +443,11 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
when 'share process, interactive'
SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_SHARE_PROCESS
else
- nil
+ raise("Unsupported service type, #{service_type}. Submit bug request to fix.")
end
end
+ # @return [Integer]
def get_start_type(start_type)
case start_type
when 'auto start'
@@ -451,7 +461,7 @@ class Chef::Provider::Service::Windows < Chef::Provider::Service
when 'system start'
SERVICE_SYSTEM_START
else
- nil
+ raise("Unsupported start type, #{start_type}. Submit bug request to fix.")
end
end
diff --git a/lib/chef/resource/windows_service.rb b/lib/chef/resource/windows_service.rb
index bcd0272b06..a085252a4c 100644
--- a/lib/chef/resource/windows_service.rb
+++ b/lib/chef/resource/windows_service.rb
@@ -28,9 +28,9 @@ class Chef
include Chef::Win32ServiceConstants
ALLOWED_START_TYPES = {
- :automatic => SERVICE_AUTO_START,
- :manual => SERVICE_DEMAND_START,
- :disabled => SERVICE_DISABLED,
+ automatic: SERVICE_AUTO_START,
+ manual: SERVICE_DEMAND_START,
+ disabled: SERVICE_DISABLED,
}
# Until #1773 is resolved, you need to manually specify the windows_service resource
@@ -62,26 +62,27 @@ class Chef
# - :manual
# - :disabled
# Reference: https://github.com/djberg96/win32-service/blob/ffi/lib/win32/windows/constants.rb#L49-L54
- property :startup_type, Integer, default: SERVICE_AUTO_START, coerce: proc { |x|
+ property :startup_type, [Symbol], equal_to: [:automatic, :manual, :disabled], default: :automatic, coerce: proc { |x|
if x.is_a?(Integer)
- x
- elsif x.is_a?(String) or x.is_a?(Symbol)
- x = x.to_sym
- ALLOWED_START_TYPES.fetch(x) do
+ ALLOWED_START_TYPES.invert.fetch(x) do
Chef::Log.warn("Unsupported startup_type #{x}, falling back to :automatic")
- SERVICE_AUTO_START
+ :automatic
end
+ elsif x.is_a?(String)
+ x.to_sym
+ else
+ x
end
}
# This only applies if startup_type is :automatic
- property :delayed_start, [Integer], default: false, coerce: proc { |x|
- if x.is_a?(TrueClass)
- 1
- elsif x.is_a?(FalseClass)
- 0
- elsif x.is_a?(Integer)
- x.zero? ? 0 : 1
+ # 1 == delayed start is enabled
+ # 0 == NO delayed start
+ property :delayed_start, [TrueClass, FalseClass], default: false, coerce: proc { |x|
+ if x.is_a?(Integer)
+ x.zero? ? false : true
+ else
+ x
end
}
@@ -90,7 +91,10 @@ class Chef
# The fully qualified path to the service binary file. The path can also
# include arguments for an auto-start service.
- property :binary_path_name, String, required: true
+ #
+ # This is required for :create and :configure actions -- intentionally
+ # not setting required: true here to support other actions
+ property :binary_path_name, String
# The names of the load ordering group of which this service is a member.
# Specify nil or an empty string if the service does not belong to a group.
diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb
index d4c451511d..6c6a50c01d 100644
--- a/spec/unit/provider/service/windows_spec.rb
+++ b/spec/unit/provider/service/windows_spec.rb
@@ -20,10 +20,64 @@
require "spec_helper"
require "mixlib/shellout"
+class Chef::ReservedNames::Win32::Security; end
+
describe Chef::Provider::Service::Windows, "load_current_resource" do
include_context "Win32"
- let(:new_resource) { Chef::Resource::WindowsService.new("chef") }
+ let(:chef_service_name) { "chef-client" }
+ let(:new_resource) { Chef::Resource::WindowsService.new(chef_service_name) }
+
+ # Actual response from Win32::Service.config_info('chef-client')
+ let(:chef_service_binary_path_name) do
+ 'C:\\opscode\\chef\\embedded\\bin\\ruby.exe C:\\opscode\\chef\\bin\\chef-windows-service'
+ end
+ let(:chef_service_config_info) do
+ double('Struct::ServiceConfigInfo',
+ service_type: 'own process',
+ start_type: 'auto start',
+ error_control: 'ignore',
+ binary_path_name: chef_service_binary_path_name,
+ load_order_group: '',
+ tag_id: 0,
+ dependencies: ['Winmgmt'],
+ service_start_name: 'LocalSystem',
+ display_name: 'Chef Client Service',
+ )
+ end
+
+ # Actual response from Win32::Service.services
+ let(:chef_service_info) do
+ double('Struct::ServiceInfo',
+ service_name: chef_service_name,
+ display_name: 'Chef Client Service',
+ service_type: 'own process',
+ current_state: 'running',
+ controls_accepted: [],
+ win32_exit_code: 1077,
+ service_specific_exit_code: 0,
+ check_point: 0,
+ wait_hint: 0,
+ binary_path_name: chef_service_binary_path_name,
+ start_type: 'auto start',
+ error_control: 'ignore',
+ load_order_group: '',
+ tag_id: 0,
+ start_name: 'LocalSystem',
+ dependencies: ['Winmgmt'],
+ description: 'Runs Chef Client on regular, configurable intervals.',
+ interactive: false,
+ pid: 0,
+ service_flags: 0,
+ reset_period: 0,
+ reboot_message: nil,
+ command: nil,
+ num_actions: 0,
+ actions: nil,
+ delayed_start: 1
+ )
+ end
+
let(:provider) do
prvdr = Chef::Provider::Service::Windows.new(new_resource,
Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new))
@@ -43,11 +97,35 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
allow(Win32::Service).to receive(:status).with(new_resource.service_name).and_return(
double("StatusStruct", :current_state => "running"))
- allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
- double("ConfigStruct", :start_type => "auto start"))
+ allow(Win32::Service).to receive(:config_info).with(new_resource.service_name)
+ .and_return(chef_service_config_info)
+
+ # Real response from Win32::Service.services
+ allow(Win32::Service).to receive(:services).and_return([
+ # Add chef_service_info to our stubbed response so our tests that are expecting the service to exist work
+ chef_service_info,
+ double('Struct::ServiceInfo', service_name: 'ACPI', display_name: 'Microsoft ACPI Driver', service_type: 'kernel driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: '\\SystemRoot\\System32\\drivers\\ACPI.sys', start_type: 'boot start', error_control: 'critical', load_order_group: 'Core', tag_id: 2, start_name: '', dependencies: [], description: '', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'cdrom', display_name: 'CD-ROM Driver', service_type: 'kernel driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: '\\SystemRoot\\System32\\drivers\\cdrom.sys', start_type: 'system start', error_control: 'normal', load_order_group: 'SCSI CDROM Class', tag_id: 3, start_name: '', dependencies: [], description: '', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'CryptSvc', display_name: 'Cryptographic Services', service_type: 'share process', current_state: 'running', controls_accepted: ['shutdown', 'stop', 'session change'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k NetworkService', start_type: 'auto start', error_control: 'normal', load_order_group: '', tag_id: 0, start_name: 'NT Authority\\NetworkService', dependencies: ['RpcSs'], description: 'Provides three management services: Catalog Database Service, which confirms the signatures of Windows files and allows new programs to be installed; Protected Root Service, which adds and removes Trusted Root Certification Authority certificates from this computer; and Automatic Root Certificate Update Service, which retrieves root certificates from Windows Update and enable scenarios such as SSL. If this service is stopped, these management services will not function properly. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 932, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 60000 }, 2 => { action_type: 'none', delay: 0 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'DcomLaunch', display_name: 'DCOM Server Process Launcher', service_type: 'share process', current_state: 'running', controls_accepted: ['session change'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k DcomLaunch', start_type: 'auto start', error_control: 'normal', load_order_group: 'COM Infrastructure', tag_id: 0, start_name: 'LocalSystem', dependencies: [], description: 'The DCOMLAUNCH service launches COM and DCOM servers in response to object activation requests. If this service is stopped or disabled, programs using COM or DCOM will not function properly. It is strongly recommended that you have the DCOMLAUNCH service running.', interactive: false, pid: 552, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 1, actions: { 1 => { action_type: 'reboot', delay: 60000 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'Dfsc', display_name: 'DFS Namespace Client Driver', service_type: 'file system driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'System32\\Drivers\\dfsc.sys', start_type: 'system start', error_control: 'normal', load_order_group: 'Network', tag_id: 0, start_name: '', dependencies: ['Mup'], description: 'Client driver for access to DFS Namespaces', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'Dhcp', display_name: 'DHCP Client', service_type: 'share process', current_state: 'running', controls_accepted: %w(shutdown stop), win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted', start_type: 'auto start', error_control: 'normal', load_order_group: 'TDI', tag_id: 0, start_name: 'NT Authority\\LocalService', dependencies: %w(NSI Tdx Afd), description: 'Registers and updates IP addresses and DNS records for this computer. If this service is stopped, this computer will not receive dynamic IP addresses and DNS updates. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 780, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 120000 }, 2 => { action_type: 'restart', delay: 300000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'EventLog', display_name: 'Windows Event Log', service_type: 'share process', current_state: 'running', controls_accepted: %w(shutdown stop), win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\System32\\svchost.exe -k LocalServiceNetworkRestricted', start_type: 'auto start', error_control: 'normal', load_order_group: 'Event Log', tag_id: 0, start_name: 'NT AUTHORITY\\LocalService', dependencies: [], description: 'This service manages events and event logs. It supports logging events, querying events, subscribing to events, archiving event logs, and managing event metadata. It can display events in both XML and plain text format. Stopping this service may compromise security and reliability of the system.', interactive: false, pid: 780, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 60000 }, 2 => { action_type: 'restart', delay: 120000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'EventSystem', display_name: 'COM+ Event System', service_type: 'share process', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalService', start_type: 'auto start', error_control: 'normal', load_order_group: '', tag_id: 0, start_name: 'NT AUTHORITY\\LocalService', dependencies: ['rpcss'], description: 'Supports System Event Notification Service (SENS), which provides automatic distribution of events to subscribing Component Object Model (COM) components. If the service is stopped, SENS will close and will not be able to provide logon and logoff notifications. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 844, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 1000 }, 2 => { action_type: 'restart', delay: 5000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'LanmanWorkstation', display_name: 'Workstation', service_type: 'share process', current_state: 'running', controls_accepted: ['pause continue', 'stop', 'power event'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\System32\\svchost.exe -k NetworkService', start_type: 'auto start', error_control: 'normal', load_order_group: 'NetworkProvider', tag_id: 0, start_name: 'NT AUTHORITY\\NetworkService', dependencies: %w(Bowser MRxSmb20 NSI), description: 'Creates and maintains client network connections to remote servers using the SMB protocol. If this service is stopped, these connections will be unavailable. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 932, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 60000 }, 2 => { action_type: 'restart', delay: 120000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'lmhosts', display_name: 'TCP/IP NetBIOS Helper', service_type: 'share process', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted', start_type: 'auto start', error_control: 'normal', load_order_group: 'TDI', tag_id: 0, start_name: 'NT AUTHORITY\\LocalService', dependencies: %w(NetBT Afd), description: 'Provides support for the NetBIOS over TCP/IP (NetBT) service and NetBIOS name resolution for clients on the network, therefore enabling users to share files, print, and log on to the network. If this service is stopped, these functions might be unavailable. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 780, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 100 }, 2 => { action_type: 'restart', delay: 100 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'MpsSvc', display_name: 'Windows Firewall', service_type: 'share process', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNoNetwork', start_type: 'auto start', error_control: 'normal', load_order_group: 'NetworkProvider', tag_id: 0, start_name: 'NT Authority\\LocalService', dependencies: %w(mpsdrv bfe), description: 'Windows Firewall helps protect your computer by preventing unauthorized users from gaining access to your computer through the Internet or a network.', interactive: false, pid: 340, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 120000 }, 2 => { action_type: 'restart', delay: 300000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'mrxsmb', display_name: 'SMB MiniRedirector Wrapper and Engine', service_type: 'file system driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'system32\\DRIVERS\\mrxsmb.sys', start_type: 'demand start', error_control: 'normal', load_order_group: 'Network', tag_id: 5, start_name: '', dependencies: ['rdbss'], description: 'Implements the framework for the SMB filesystem redirector', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'Ntfs', display_name: 'Ntfs', service_type: 'file system driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: '', start_type: 'demand start', error_control: 'normal', load_order_group: 'Boot File System', tag_id: 0, start_name: '', dependencies: [], description: '', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'Tcpip', display_name: 'TCP/IP Protocol Driver', service_type: 'kernel driver', current_state: 'running', controls_accepted: ['stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: '\\SystemRoot\\System32\\drivers\\tcpip.sys', start_type: 'boot start', error_control: 'normal', load_order_group: 'PNP_TDI', tag_id: 3, start_name: '', dependencies: [], description: 'TCP/IP Protocol Driver', interactive: false, pid: 0, service_flags: 0, reset_period: 0, reboot_message: nil, command: nil, num_actions: 0, actions: nil, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'W32Time', display_name: 'Windows Time', service_type: 'share process', current_state: 'running', controls_accepted: ['netbind change', 'param change', 'shutdown', 'stop', 'hardware profile change', 'power event'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalService', start_type: 'demand start', error_control: 'normal', load_order_group: '', tag_id: 0, start_name: 'NT AUTHORITY\\LocalService', dependencies: [], description: 'Maintains date and time synchronization on all clients and servers in the network. If this service is stopped, date and time synchronization will be unavailable. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 844, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 60000 }, 2 => { action_type: 'restart', delay: 120000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'Winmgmt', display_name: 'Windows Management Instrumentation', service_type: 'share process', current_state: 'running', controls_accepted: ['pause continue', 'shutdown', 'stop'], win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k netsvcs', start_type: 'auto start', error_control: 'ignore', load_order_group: '', tag_id: 0, start_name: 'localSystem', dependencies: ['RPCSS'], description: 'Provides a common interface and object model to access management information about operating system, devices, applications and services. If this service is stopped, most Windows-based software will not function properly. If this service is disabled, any services that explicitly depend on it will fail to start.', interactive: false, pid: 812, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 120000 }, 2 => { action_type: 'restart', delay: 300000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ double('Struct::ServiceInfo', service_name: 'WinRM', display_name: 'Windows Remote Management (WS-Management)', service_type: 'share process', current_state: 'running', controls_accepted: %w(shutdown stop), win32_exit_code: 0, service_specific_exit_code: 0, check_point: 0, wait_hint: 0, binary_path_name: 'C:\\Windows\\System32\\svchost.exe -k NetworkService', start_type: 'auto start', error_control: 'normal', load_order_group: '', tag_id: 0, start_name: 'NT AUTHORITY\\NetworkService', dependencies: %w(RPCSS HTTP), description: 'Windows Remote Management (WinRM) service implements the WS-Management protocol for remote management. WS-Management is a standard web services protocol used for remote software and hardware management. The WinRM service listens on the network for WS-Management requests and processes them. The WinRM Service needs to be configured with a listener using winrm.cmd command line tool or through Group Policy in order for it to listen over the network. The WinRM service provides access to WMI data and enables event collection. Event collection and subscription to events require that the service is running. WinRM messages use HTTP and HTTPS as transports. The WinRM service does not depend on IIS but is preconfigured to share a port with IIS on the same machine. The WinRM service reserves the /wsman URL prefix. To prevent conflicts with IIS, administrators should ensure that any websites hosted on IIS do not use the /wsman URL prefix.', interactive: false, pid: 932, service_flags: 0, reset_period: 86400, reboot_message: nil, command: nil, num_actions: 3, actions: { 1 => { action_type: 'restart', delay: 120000 }, 2 => { action_type: 'restart', delay: 300000 }, 3 => { action_type: 'none', delay: 0 } }, delayed_start: 0),
+ ])
allow(Win32::Service).to receive(:exists?).and_return(true)
allow(Win32::Service).to receive(:configure).and_return(Win32::Service)
allow(Chef::ReservedNames::Win32::Security).to receive(:get_account_right).and_return([])
+ allow(Chef::ReservedNames::Win32::Security).to receive(:add_account_right).with('LocalSystem', 'SeServiceLogonRight').and_return(0)
end
after(:each) do
@@ -58,28 +136,365 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
it "sets the current resources service name to the new resources service name" do
provider.load_current_resource
- expect(provider.current_resource.service_name).to eq("chef")
+ expect(provider.current_resource.service_name).to eq(chef_service_name)
end
it "returns the current resource" do
expect(provider.load_current_resource).to equal(provider.current_resource)
end
- it "sets the current resources status" do
- provider.load_current_resource
- expect(provider.current_resource.running).to be_truthy
- end
-
it "sets the current resources start type" do
provider.load_current_resource
expect(provider.current_resource.enabled).to be_truthy
end
- it "does not set the current resources start type if it is neither AUTO START or DISABLED" do
- allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
- double("ConfigStruct", :start_type => "manual"))
- provider.load_current_resource
- expect(provider.current_resource.enabled).to be_nil
+ context "service does not exist" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(false)
+ end
+
+ %w(running enabled startup_type error_control binary_path_name
+ load_order_group dependencies run_as_user display_name ).each do |prop|
+ it "does not set #{prop}" do
+ expect(provider.current_resource.running).to be_nil
+ end
+ end
+ end
+
+ context "service exists" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(true)
+ allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
+ double("Struct::ServiceConfigInfo",
+ service_type: 'share process',
+ start_type: 'demand start',
+ error_control: 'normal',
+ binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted',
+ load_order_group: 'TDI',
+ tag_id: 0,
+ dependencies: %w(NSI Tdx Afd),
+ service_start_name: 'NT Authority\\LocalService',
+ display_name: 'DHCP Client'
+ ))
+ end
+
+ context 'startup_type is neither :automatic or :disabled' do
+ before do
+ allow(Win32::Service).to receive(:config_info).with(new_resource.service_name).and_return(
+ double("Struct::ServiceConfigInfo",
+ service_type: 'share process',
+ start_type: 'demand start',
+ error_control: 'normal',
+ binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted',
+ load_order_group: 'TDI',
+ tag_id: 0,
+ dependencies: %w(NSI Tdx Afd),
+ service_start_name: 'NT Authority\\LocalService',
+ display_name: 'DHCP Client'
+ ))
+ end
+
+ it "does not set the current resources enabled" do
+ provider.load_current_resource
+ expect(provider.current_resource.enabled).to be_nil
+ end
+ end
+
+ it "sets the current resources running to true if it's running" do
+ allow(provider).to receive(:current_state).and_return("running")
+ provider.load_current_resource
+ expect(provider.current_resource.running).to be true
+ end
+
+ it "sets the current resources running to false if it's in any other state" do
+ allow(provider).to receive(:current_state).and_return("other state")
+ provider.load_current_resource
+ expect(provider.current_resource.running).to be false
+ end
+
+ it "sets startup_type" do
+ expect(provider.current_resource.startup_type).to be_truthy
+ end
+
+ it "sets error_control" do
+ provider.load_current_resource
+ expect(provider.current_resource.error_control).to be_truthy
+ end
+
+ it "sets binary_path_name" do
+ provider.load_current_resource
+ expect(provider.current_resource.binary_path_name).to be_truthy
+ end
+
+ it "sets load_order_group" do
+ provider.load_current_resource
+ expect(provider.current_resource.load_order_group).to be_truthy
+ end
+
+ it "sets dependencies" do
+ provider.load_current_resource
+ expect(provider.current_resource.dependencies).to be_truthy
+ end
+
+ it "sets run_as_user" do
+ provider.load_current_resource
+ expect(provider.current_resource.run_as_user).to be_truthy
+ end
+
+ it "sets display_name" do
+ provider.load_current_resource
+ expect(provider.current_resource.display_name).to be_truthy
+ end
+
+ it "sets delayed start to true if delayed start is enabled" do
+ allow(chef_service_info).to receive(:delayed_start).and_return(1)
+ provider.load_current_resource
+ expect(provider.current_resource.delayed_start).to be true
+ end
+
+ it "sets delayed start to false if delayed start is disabled" do
+ allow(chef_service_info).to receive(:delayed_start).and_return(0)
+ provider.load_current_resource
+ expect(provider.current_resource.delayed_start).to be false
+ end
+ end
+
+ describe Chef::Provider::Service::Windows, "action_create" do
+ before do
+ provider.new_resource.binary_path_name = chef_service_binary_path_name
+ end
+
+ context "service exists" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(true)
+ end
+
+ it "logs debug message" do
+ expect(Chef::Log).to receive(:debug).with("windows_service[#{chef_service_name}] already exists - nothing to do")
+ provider.action_create
+ end
+
+ it "does not converge" do
+ provider.action_create
+ expect(provider.resource_updated?).to be false
+ end
+
+ it "does not create service" do
+ expect(Win32::Service).to_not receive(:new)
+ provider.action_create
+ end
+
+ it "does not call converge_delayed_start" do
+ expect(provider).to_not receive(:converge_delayed_start)
+ provider.action_create
+ end
+ end
+
+ context "service does not exist" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(false)
+ allow(Win32::Service).to receive(:new).with(anything).and_return(true)
+ end
+
+ it "converges resource" do
+ provider.action_create
+ expect(provider.resource_updated?).to be true
+ end
+
+ it "creates service" do
+ expect(Win32::Service).to receive(:new)
+ provider.action_create
+ end
+
+ it "creates service with correct configuration" do
+ expect(Win32::Service).to receive(:new).with(
+ service_name: chef_service_name,
+ service_type: 16,
+ start_type: 2,
+ error_control: 1,
+ binary_path_name: chef_service_binary_path_name,
+ service_start_name: 'LocalSystem',
+ desired_access: 983551,
+ )
+ provider.action_create
+ end
+
+ it "calls converge_delayed_start" do
+ expect(provider).to receive(:converge_delayed_start)
+ provider.action_create
+ end
+ end
+ end
+
+ describe Chef::Provider::Service::Windows, "action_delete" do
+ context "service exists" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(true)
+ allow(Win32::Service).to receive(:delete).with(chef_service_name).and_return(true)
+ end
+
+ it "converges resource" do
+ provider.action_delete
+ expect(provider.resource_updated?).to be true
+ end
+
+ it "deletes service" do
+ expect(Win32::Service).to receive(:delete).with(chef_service_name)
+ provider.action_delete
+ end
+ end
+
+ context "service does not exist" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(false)
+ end
+
+ it "logs debug message" do
+ expect(Chef::Log).to receive(:debug).with("windows_service[#{chef_service_name}] does not exist - nothing to do")
+ provider.action_delete
+ end
+
+ it "does not converge" do
+ provider.action_delete
+ expect(provider.resource_updated?).to be false
+ end
+
+ it "does not delete service" do
+ expect(Win32::Service).to_not receive(:delete)
+ provider.action_delete
+ end
+ end
+ end
+
+ describe Chef::Provider::Service::Windows, "action_configure" do
+ context "service exists" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(true)
+ allow(Win32::Service).to receive(:configure).with(anything).and_return(true)
+ end
+
+ it "works around #6300 if run_as_user is default" do
+ new_resource.run_as_user = new_resource.class.properties[:run_as_user].default
+ expect(provider.new_resource).to receive(:run_as_user=)
+ .with(new_resource.class.properties[:run_as_user].default)
+ provider.action_configure
+ end
+
+ # Attributes that are Strings
+ %i(binary_path_name load_order_group dependencies run_as_user
+ display_name).each do |attr|
+ it "configures service if #{attr} has changed" do
+ provider.current_resource.send("#{attr}=", "old value")
+ provider.new_resource.send("#{attr}=", "new value")
+
+ expect(Win32::Service).to receive(:configure)
+ provider.action_configure
+ end
+ end
+
+ # Attributes that are Integers
+ %i(service_type error_control).each do |attr|
+ it "configures service if #{attr} has changed" do
+ provider.current_resource.send("#{attr}=", 1)
+ provider.new_resource.send("#{attr}=", 2)
+
+ expect(Win32::Service).to receive(:configure)
+ provider.action_configure
+ end
+ end
+
+ it "configures service if startup_type has changed" do
+ provider.current_resource.startup_type = :automatic
+ provider.new_resource.startup_type = :manual
+
+ expect(Win32::Service).to receive(:configure)
+ provider.action_configure
+ end
+
+ it "calls converge_delayed_start" do
+ expect(provider).to receive(:converge_delayed_start)
+ provider.action_configure
+ end
+ end
+
+ context "service does not exist" do
+ before do
+ allow(Win32::Service).to receive(:exists?).with(chef_service_name).and_return(false)
+ end
+
+ it "logs warning" do
+ expect(Chef::Log).to receive(:warn)
+ .with("windows_service[#{chef_service_name}] does not exist. Maybe you need to prepend action :create")
+ provider.action_configure
+ end
+
+ it "does not converge" do
+ provider.action_configure
+ expect(provider.resource_updated?).to be false
+ end
+
+ it "does not convigure service" do
+ expect(Win32::Service).to_not receive(:configure)
+ provider.action_configure
+ end
+
+ it "does not call converge_delayed_start" do
+ expect(provider).to_not receive(:converge_delayed_start)
+ provider.action_configure
+ end
+ end
+ end
+
+ describe Chef::Provider::Service::Windows, "converge_delayed_start" do
+ before do
+ allow(Win32::Service).to receive(:configure).and_return(true)
+ end
+
+ it "works around #6300 if delayed_start is default" do
+ new_resource.delayed_start = new_resource.class.properties[:delayed_start].default
+ expect(provider.new_resource).to receive(:delayed_start=)
+ .with(new_resource.class.properties[:delayed_start].default)
+ provider.send(:converge_delayed_start)
+ end
+
+ context "delayed start needs to be updated" do
+ before do
+ provider.current_resource.delayed_start = false
+ provider.new_resource.delayed_start = true
+ end
+
+ it "configures delayed start" do
+ expect(Win32::Service).to receive(:configure)
+ provider.send(:converge_delayed_start)
+ end
+
+ it "configures delayed start with correct params" do
+ expect(Win32::Service).to receive(:configure).with(service_name: chef_service_name, delayed_start: 1)
+ provider.send(:converge_delayed_start)
+ end
+
+ it "converges resource" do
+ provider.send(:converge_delayed_start)
+ expect(provider.resource_updated?).to be true
+ end
+ end
+
+ context "delayed start does not need to be updated" do
+ before do
+ provider.current_resource.delayed_start = false
+ provider.new_resource.delayed_start = false
+ end
+
+ it "does not configure delayed start" do
+ expect(Win32::Service).to_not receive(:configure)
+ provider.send(:converge_delayed_start)
+ end
+
+ it "does not converge" do
+ provider.send(:converge_delayed_start)
+ expect(provider.resource_updated?).to be false
+ end
+ end
end
describe Chef::Provider::Service::Windows, "start_service" do
@@ -90,7 +505,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
end
it "calls the start command if one is specified" do
- new_resource.start_command "sc start chef"
+ new_resource.start_command "sc start #{chef_service_name}"
expect(provider).to receive(:shell_out!).with("#{new_resource.start_command}").and_return("Starting custom service")
provider.start_service
expect(new_resource.updated_by_last_action?).to be_truthy
@@ -185,7 +600,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
end
it "calls the stop command if one is specified" do
- new_resource.stop_command "sc stop chef"
+ new_resource.stop_command "sc stop #{chef_service_name}"
expect(provider).to receive(:shell_out!).with("#{new_resource.stop_command}").and_return("Stopping custom service")
provider.stop_service
expect(new_resource.updated_by_last_action?).to be_truthy
@@ -369,17 +784,17 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
end
describe Chef::Provider::Service::Windows, "action_configure_startup" do
- { :automatic => "auto start", :manual => "demand start", :disabled => "disabled" }.each do |type, win32|
+ %i[automatic manual disabled].each do |type|
it "sets the startup type to #{type} if it is something else" do
new_resource.startup_type(type)
- allow(provider).to receive(:current_start_type).and_return("fire")
+ allow(provider).to receive(:current_startup_type).and_return(:fire)
expect(provider).to receive(:set_startup_type).with(type)
provider.action_configure_startup
end
it "leaves the startup type as #{type} if it is already set" do
new_resource.startup_type(type)
- allow(provider).to receive(:current_start_type).and_return(win32)
+ allow(provider).to receive(:current_startup_type).and_return(type)
expect(provider).not_to receive(:set_startup_type).with(type)
provider.action_configure_startup
end
diff --git a/spec/unit/resource/windows_service_spec.rb b/spec/unit/resource/windows_service_spec.rb
index f192d8375c..1b6b5e76d6 100644
--- a/spec/unit/resource/windows_service_spec.rb
+++ b/spec/unit/resource/windows_service_spec.rb
@@ -42,4 +42,29 @@ describe Chef::Resource::WindowsService, "initialize" do
resource.action :configure_startup
expect(resource.action).to eq([:configure_startup])
end
+
+ # Attributes that are Strings
+ %i(description service_name binary_path_name load_order_group dependencies
+ run_as_user run_as_password display_name).each do |prop|
+ it "support setting #{prop}" do
+ resource.send("#{prop}=", "some value")
+ expect(resource.send(prop)).to eq("some value")
+ end
+ end
+
+ # Attributes that are Integers
+ %i(desired_access error_control service_type).each do |prop|
+ it "support setting #{prop}" do
+ resource.send("#{prop}=", 1)
+ expect(resource.send(prop)).to eq(1)
+ end
+ end
+
+ # Attributes that are Booleans
+ %i(delayed_start).each do |prop|
+ it "support setting #{prop}" do
+ resource.send("#{prop}=", true)
+ expect(resource.send(prop)).to eq(true)
+ end
+ end
end