kitchen-dsc 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/spec/spec_helper.rb CHANGED
@@ -1,20 +1,74 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #
2
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
- #
4
- # Copyright (C) 2012, Fletcher Nichol
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
4
+ # Copyright (C) 2014 Steven Murawski
11
5
  #
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.
6
+ # Licensed under the Apache 2 License.
7
+ # See LICENSE for more details
8
+
9
+ # Coverage must be started before any library code is loaded, otherwise methods
10
+ # defined at require-time are recorded as uncovered. Set COVERAGE=false to skip
11
+ # it (useful when bisecting or profiling a single spec file).
12
+ unless ENV["COVERAGE"] == "false"
13
+ require "simplecov"
14
+
15
+ SimpleCov.start do
16
+ enable_coverage :branch
17
+ add_filter "/spec/"
18
+ track_files "lib/**/*.rb"
19
+ # Deliberately no `minimum_coverage`: coverage is a diagnostic here, not a
20
+ # gate. CI must never fail because a percentage moved.
21
+ end
22
+ end
23
+
24
+ require "kitchen"
25
+ require "kitchen/provisioner/dsc"
26
+ require "kitchen-dsc/version"
27
+
28
+ require "stringio"
29
+ require "tmpdir"
30
+
31
+ Dir[File.expand_path("support/**/*.rb", __dir__)].sort.each { |file| require file }
32
+
33
+ RSpec.configure do |config|
34
+ config.include KitchenHelpers
35
+
36
+ # rspec-expectations
37
+ config.expect_with :rspec do |expectations|
38
+ expectations.syntax = :expect
39
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
40
+ # The provisioner emits multi-kilobyte PowerShell scripts; truncating the
41
+ # diff on failure hides the one line that actually differs.
42
+ expectations.max_formatted_output_length = nil
43
+ end
44
+
45
+ # rspec-mocks
46
+ config.mock_with :rspec do |mocks|
47
+ mocks.verify_partial_doubles = true
48
+ end
49
+
50
+ config.shared_context_metadata_behavior = :apply_to_host_groups
51
+ config.filter_run_when_matching :focus
52
+ config.example_status_persistence_file_path = "spec/examples.txt"
53
+ config.disable_monkey_patching!
54
+ config.raise_errors_for_deprecations!
55
+
56
+ config.default_formatter = "doc" if config.files_to_run.one?
57
+
58
+ config.order = :random
59
+ Kernel.srand config.seed
60
+
61
+ # Ruby warnings are opt-in: test-kitchen and its transitive dependencies emit
62
+ # enough of their own to drown out anything this gem causes.
63
+ config.warnings = ENV["RSPEC_WARNINGS"] == "true"
17
64
 
18
- gem "minitest"
65
+ # Keep Test Kitchen's global logger out of the spec output. Individual
66
+ # examples get their own logger via KitchenHelpers#kitchen_log.
67
+ config.before(:suite) do
68
+ Kitchen.logger = Kitchen::Logger.new(stdout: StringIO.new, level: :debug)
69
+ end
19
70
 
20
- require "minitest/autorun"
71
+ config.after do
72
+ cleanup_kitchen_tmpdirs
73
+ end
74
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "stringio"
5
+ require "tmpdir"
6
+
7
+ require "kitchen/driver/dummy"
8
+ require "kitchen/transport/dummy"
9
+ require "kitchen/verifier/dummy"
10
+
11
+ # Helpers for exercising {Kitchen::Provisioner::Dsc} against a genuine
12
+ # {Kitchen::Instance}.
13
+ #
14
+ # The provisioner reads most of its behaviour out of `config`, and Test Kitchen
15
+ # populates `config` in two passes: static `default_config` values, then lazy
16
+ # `default_config` blocks that are only evaluated once an instance is attached
17
+ # (`Kitchen::Provisioner::Dsc` uses one to derive `:configuration_name` from the
18
+ # suite name). Building a real instance with the stock dummy driver, transport
19
+ # and verifier gets both passes for free; a hand-rolled double would silently
20
+ # skip the second.
21
+ module KitchenHelpers
22
+ # Default `:root_path` used by the specs. Test Kitchen's Windows default,
23
+ # spelled out here so expectations can refer to it by name.
24
+ DEFAULT_ROOT_PATH = 'C:\\kitchen'
25
+
26
+ # Name of the suite the built instance runs. Override with `let(:suite_name)`
27
+ # to exercise the `:configuration_name` default, which is derived from it.
28
+ #
29
+ # @return [String] the suite name
30
+ def suite_name
31
+ "default"
32
+ end
33
+
34
+ # Name of the platform the built instance runs. Anything starting with `win`
35
+ # gives the instance a `powershell` shell type; override with
36
+ # `let(:platform_name)` to test the bourne path.
37
+ #
38
+ # @return [String] the platform name
39
+ def platform_name
40
+ "windows-2022"
41
+ end
42
+
43
+ # Builds a provisioner wired to a real instance.
44
+ #
45
+ # @param config [Hash] provisioner configuration, merged over the defaults
46
+ # @return [Kitchen::Provisioner::Dsc] a finalized provisioner
47
+ def build_provisioner(config = {})
48
+ defaults = { kitchen_root:, root_path: DEFAULT_ROOT_PATH }
49
+ provisioner = Kitchen::Provisioner::Dsc.new(defaults.merge(config))
50
+ build_instance(provisioner)
51
+ provisioner
52
+ end
53
+
54
+ # Builds the {Kitchen::Instance} that owns +provisioner+.
55
+ #
56
+ # Constructing the instance is what calls `Provisioner#finalize_config!`, so
57
+ # this is also what exercises the provisioner's LCM configuration merge.
58
+ #
59
+ # @param provisioner [Kitchen::Provisioner::Base] the provisioner under test
60
+ # @return [Kitchen::Instance] the built instance
61
+ def build_instance(provisioner)
62
+ state_file = Kitchen::StateFile.new(kitchen_root, "#{suite_name}-#{platform_name}")
63
+
64
+ Kitchen::Instance.new(
65
+ suite: Kitchen::Suite.new(name: suite_name),
66
+ platform: Kitchen::Platform.new(name: platform_name),
67
+ driver: Kitchen::Driver::Dummy.new,
68
+ provisioner:,
69
+ transport: Kitchen::Transport::Dummy.new,
70
+ verifier: Kitchen::Verifier::Dummy.new,
71
+ lifecycle_hooks: Kitchen::LifecycleHooks.new({}, state_file),
72
+ state_file:,
73
+ logger: kitchen_logger
74
+ )
75
+ end
76
+
77
+ # Creates the provisioner's sandbox and registers it for cleanup.
78
+ #
79
+ # {Kitchen::Provisioner::Base#create_sandbox} mints its own temporary
80
+ # directory, so it has to be tracked separately from {#kitchen_root}.
81
+ #
82
+ # @param provisioner [Kitchen::Provisioner::Dsc] the provisioner under test
83
+ # @return [String] absolute path to the created sandbox
84
+ def create_sandbox_for(provisioner)
85
+ provisioner.create_sandbox
86
+ register_tmpdir(provisioner.sandbox_path)
87
+ end
88
+
89
+ # The temporary directory standing in for the user's cookbook/module root.
90
+ #
91
+ # @return [String] absolute path to the kitchen root
92
+ def kitchen_root
93
+ @kitchen_root ||= register_tmpdir(Dir.mktmpdir("kitchen-dsc-root-"))
94
+ end
95
+
96
+ # Everything the provisioner has logged during the current example.
97
+ #
98
+ # @return [String] captured log output
99
+ def kitchen_log
100
+ log_device.string
101
+ end
102
+
103
+ # @return [Kitchen::Logger] a debug-level logger writing to {#log_device}
104
+ def kitchen_logger
105
+ @kitchen_logger ||= Kitchen::Logger.new(stdout: log_device, level: :debug)
106
+ end
107
+
108
+ # Writes a file beneath {#kitchen_root}, creating parent directories.
109
+ #
110
+ # @param relative_path [String] path relative to the kitchen root
111
+ # @param content [String] file contents
112
+ # @return [String] the absolute path written
113
+ def write_kitchen_file(relative_path, content = "# fixture\n")
114
+ path = File.join(kitchen_root, relative_path)
115
+ FileUtils.mkdir_p(File.dirname(path))
116
+ File.write(path, content)
117
+ path
118
+ end
119
+
120
+ # Lists every file under +dir+ as paths relative to it.
121
+ #
122
+ # @param dir [String] directory to walk
123
+ # @return [Array<String>] sorted relative paths of regular files
124
+ def files_under(dir)
125
+ Dir.glob(File.join(dir, "**/*"), File::FNM_DOTMATCH)
126
+ .reject { |path| File.directory?(path) }
127
+ .map { |path| path.sub("#{dir}/", "") }
128
+ .sort
129
+ end
130
+
131
+ # Registers a directory for removal at the end of the example.
132
+ #
133
+ # @param path [String] directory to remove later
134
+ # @return [String] +path+, for chaining
135
+ def register_tmpdir(path)
136
+ kitchen_tmpdirs << path
137
+ path
138
+ end
139
+
140
+ # Removes every directory registered during the example.
141
+ #
142
+ # @return [void]
143
+ def cleanup_kitchen_tmpdirs
144
+ kitchen_tmpdirs.each { |path| FileUtils.remove_entry(path, true) }
145
+ kitchen_tmpdirs.clear
146
+ end
147
+
148
+ private
149
+
150
+ # @return [StringIO] backing device for {#kitchen_logger}
151
+ def log_device
152
+ @log_device ||= StringIO.new
153
+ end
154
+
155
+ # @return [Array<String>] directories to clean up after the example
156
+ def kitchen_tmpdirs
157
+ @kitchen_tmpdirs ||= []
158
+ end
159
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-dsc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Test Kitchen Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-28 00:00:00.000000000 Z
11
+ date: 2026-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dsc_lcm_configuration
@@ -45,13 +45,19 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".github/CODEOWNERS"
48
49
  - ".github/dependabot.yml"
49
50
  - ".github/workflows/lint.yml"
50
51
  - ".github/workflows/publish.yaml"
51
52
  - ".gitignore"
52
53
  - ".markdownlint.yaml"
54
+ - ".release-please-manifest.json"
55
+ - ".rspec"
53
56
  - ".rubocop.yml"
57
+ - ".yamllint"
58
+ - ".yardopts"
54
59
  - CHANGELOG.md
60
+ - CONTRIBUTING.md
55
61
  - Gemfile
56
62
  - LICENSE
57
63
  - README.md
@@ -59,11 +65,12 @@ files:
59
65
  - kitchen-dsc.gemspec
60
66
  - lib/kitchen-dsc/version.rb
61
67
  - lib/kitchen/provisioner/dsc.rb
62
- - lib/kitchen/provisioner/dsc_lcm/lcm_base.rb
63
- - lib/kitchen/provisioner/dsc_lcm/lcm_v4.rb
64
- - lib/kitchen/provisioner/dsc_lcm/lcm_v5.rb
68
+ - release-please-config.json
65
69
  - renovate.json
70
+ - spec/kitchen/provisioner/dsc_spec.rb
71
+ - spec/kitchen_dsc/version_spec.rb
66
72
  - spec/spec_helper.rb
73
+ - spec/support/kitchen_helpers.rb
67
74
  homepage: https://github.com/test-kitchen/kitchen-dsc
68
75
  licenses:
69
76
  - Apache-2.0
@@ -76,16 +83,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
83
  requirements:
77
84
  - - ">="
78
85
  - !ruby/object:Gem::Version
79
- version: '0'
86
+ version: '3.1'
80
87
  required_rubygems_version: !ruby/object:Gem::Requirement
81
88
  requirements:
82
89
  - - ">="
83
90
  - !ruby/object:Gem::Version
84
91
  version: '0'
85
92
  requirements: []
86
- rubygems_version: 3.4.10
93
+ rubygems_version: 3.5.9
87
94
  signing_key:
88
95
  specification_version: 4
89
96
  summary: PowerShell DSC provisioner for test-kitchen
90
- test_files:
91
- - spec/spec_helper.rb
97
+ test_files: []
@@ -1,86 +0,0 @@
1
- #
2
- # Author:: Steven Murawski (<steven.murawski@gmail.com>)
3
- #
4
- # Copyright (C) 2014 Steven Murawski
5
- #
6
- # Licensed under the Apache 2 License.
7
- # See LICENSE for more details
8
-
9
- require_relative "lcm_v4"
10
- require_relative "lcm_v5"
11
-
12
- module Kitchen
13
- module Provisioner
14
- module DscLcm
15
- class LcmBase
16
-
17
- def lcm_properties
18
- {
19
- allow_module_overwrite: false,
20
- certificate_id: nil,
21
- configuration_mode: "ApplyAndAutoCorrect",
22
- configuration_mode_frequency_mins: 30,
23
- reboot_if_needed: false,
24
- refresh_mode: "PUSH",
25
- refresh_frequency_mins: 15,
26
- }
27
- end
28
-
29
- def initialize(config = {})
30
- @certificate_id = nil
31
- lcm_properties.each do |setting, value|
32
- send(setting, value)
33
- end
34
-
35
- config.each do |setting, value|
36
- send(setting, value)
37
- end
38
- end
39
-
40
- def method_missing(name, *args)
41
- return super unless lcm_properties.keys.include?(name)
42
-
43
- if args.length == 1
44
- instance_variable_set("@#{name}", args.first)
45
- else
46
- instance_variable_get("@#{name}")
47
- end
48
- end
49
-
50
- def certificate_id(value = nil)
51
- if value.nil?
52
- @certificate_id.nil? ? "$null" : "'#{@certificate_id}'"
53
- else
54
- @certificate_id = value
55
- end
56
- end
57
-
58
- def lcm_config
59
- hash = {}
60
- lcm_properties.keys.each do |key|
61
- hash[key] = send(key)
62
- end
63
- hash
64
- end
65
-
66
- def lcm_configuration_script
67
- <<-LCMSETUP
68
- configuration SetupLCM
69
- {
70
- LocalConfigurationManager
71
- {
72
- AllowModuleOverwrite = [bool]::Parse('#{allow_module_overwrite}')
73
- CertificateID = #{certificate_id}
74
- ConfigurationMode = '#{configuration_mode}'
75
- ConfigurationModeFrequencyMins = #{configuration_mode_frequency_mins}
76
- RebootNodeIfNeeded = [bool]::Parse('#{reboot_if_needed}')
77
- RefreshFrequencyMins = #{refresh_frequency_mins}
78
- RefreshMode = '#{refresh_mode}'
79
- }
80
- }
81
- LCMSETUP
82
- end
83
- end
84
- end
85
- end
86
- end
@@ -1,52 +0,0 @@
1
- #
2
- # Author:: Steven Murawski (<steven.murawski@gmail.com>)
3
- #
4
- # Copyright (C) 2014 Steven Murawski
5
- #
6
- # Licensed under the Apache 2 License.
7
- # See LICENSE for more details
8
-
9
- require_relative "lcm_base"
10
-
11
- module Kitchen
12
- module Provisioner
13
- module DscLcm
14
- class LcmV4 < LcmBase
15
-
16
- def lcm_properties
17
- {
18
- action_after_reboot: "StopConfiguration",
19
- allow_module_overwrite: false,
20
- certificate_id: nil,
21
- configuration_mode: "ApplyAndAutoCorrect",
22
- configuration_mode_frequency_mins: 30,
23
- debug_mode: "All",
24
- reboot_if_needed: false,
25
- refresh_mode: "PUSH",
26
- refresh_frequency_mins: 15,
27
- }
28
- end
29
-
30
- def lcm_configuration_script
31
- <<-LCMSETUP
32
- configuration SetupLCM
33
- {
34
- LocalConfigurationManager
35
- {
36
- ActionAfterReboot = '#{action_after_reboot}'
37
- AllowModuleOverwrite = [bool]::Parse('#{allow_module_overwrite}')
38
- CertificateID = #{certificate_id}
39
- ConfigurationMode = '#{configuration_mode}'
40
- ConfigurationModeFrequencyMins = #{configuration_mode_frequency_mins}
41
- DebugMode = '#{debug_mode}'
42
- RebootNodeIfNeeded = [bool]::Parse('#{reboot_if_needed}')
43
- RefreshFrequencyMins = #{refresh_frequency_mins}
44
- RefreshMode = '#{refresh_mode}'
45
- }
46
- }
47
- LCMSETUP
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,53 +0,0 @@
1
- #
2
- # Author:: Steven Murawski (<steven.murawski@gmail.com>)
3
- #
4
- # Copyright (C) 2014 Steven Murawski
5
- #
6
- # Licensed under the Apache 2 License.
7
- # See LICENSE for more details
8
-
9
- require_relative "lcm_base"
10
-
11
- module Kitchen
12
- module Provisioner
13
- module DscLcm
14
- class LcmV5 < LcmBase
15
-
16
- def lcm_properties
17
- {
18
- action_after_reboot: "StopConfiguration",
19
- allow_module_overwrite: false,
20
- certificate_id: nil,
21
- configuration_mode: "ApplyAndAutoCorrect",
22
- configuration_mode_frequency_mins: 15,
23
- debug_mode: "All",
24
- reboot_if_needed: false,
25
- refresh_mode: "PUSH",
26
- refresh_frequency_mins: 30,
27
- }
28
- end
29
-
30
- def lcm_configuration_script
31
- <<-LCMSETUP
32
- [DSCLocalConfigurationManager()]
33
- configuration SetupLCM
34
- {
35
- Settings
36
- {
37
- ActionAfterReboot = '#{action_after_reboot}'
38
- AllowModuleOverwrite = [bool]::Parse('#{allow_module_overwrite}')
39
- CertificateID = #{certificate_id}
40
- ConfigurationMode = '#{configuration_mode}'
41
- ConfigurationModeFrequencyMins = #{configuration_mode_frequency_mins}
42
- DebugMode = '#{debug_mode}'
43
- RebootNodeIfNeeded = [bool]::Parse('#{reboot_if_needed}')
44
- RefreshFrequencyMins = #{refresh_frequency_mins}
45
- RefreshMode = '#{refresh_mode}'
46
- }
47
- }
48
- LCMSETUP
49
- end
50
- end
51
- end
52
- end
53
- end