kitchen-pester 0.5.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fbb89787809d137742a16f65d796fc8c5d718e50
4
- data.tar.gz: e83b27e18475e6c5e2c19432831e27ec44402e6d
3
+ metadata.gz: 3545642684f7cc181d1b44232885c7093c43f108
4
+ data.tar.gz: 5074d03f0cc3b4537a09e4058ca046dff0d6c7dd
5
5
  SHA512:
6
- metadata.gz: f64ff2bca5cabb2e8bb274d1c504ce90534486c22ae55ac9e6b19e8e7a7c42892cc466a2cc25174581ff3b5b404dc40994a0571c81da759092241c90009d97bf
7
- data.tar.gz: 8818549361ffe6e7c31d2626f9b1e982a9313a043596cd8e0fc3d07b5ccc53ee67fd45fcfacc3b3f6699477bc295c399565712b4092631aca03fddbff86dc8b9
6
+ metadata.gz: 1a0c25c85991c7f8b84c9b8ebfd70ecef2aec428f3c65f2009a3033d89912345b983d7d3eb00ec34ee84aab2555ee247af795901883c950d6300466fc269451d
7
+ data.tar.gz: ad5537103ecda5373ca7ae0091ad5c250a9c66484c451ba5cce3b84f32183c4055accc50855de4ba5572a72d6b8ad5e7f2c3ae2664a3a044b4ae570eaf5c8af7
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in kitchen-pester.gemspec
4
- gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in kitchen-pester.gemspec
4
+ gemspec
data/LICENSE CHANGED
@@ -1,22 +1,22 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2015 Steven Murawski
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
22
-
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Steven Murawski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md CHANGED
@@ -1,36 +1,36 @@
1
- [![Gem Version](https://badge.fury.io/rb/kitchen-pester.svg)](http://badge.fury.io/rb/kitchen-pester)
2
- # Kitchen::Pester
3
-
4
- Execute [Pester](https://github.com/pester/Pester) tests right from Test-Kitchen, without having to transit the Busser layer.
5
-
6
- ## Usage
7
-
8
- Either
9
- ```
10
- gem install kitchen-pester
11
- ```
12
- or include
13
- ```
14
- gem 'kitchen-pester'
15
- ```
16
- in your Gemfile.
17
-
18
- In your .kitchen.yml include
19
- ```
20
- verifier:
21
- name: pester
22
- ```
23
- This can be a top-level declaration, a per-node declaration, or a per-suite declaration.
24
-
25
- ### Options
26
-
27
- * `restart_winrm` - boolean, default is false. This is primarily to support powershell v2 scenarios. If Pester is not being found, enable this option.
28
- * `test_folder` - string, default is nil. `test-folder` allows you to specify a custom path (the default is ./test/integration/) for your integration tests. This can be an absolute path or relative to the root of the folder kitchen is running from. This path must exist.
29
-
30
- ## Contributing
31
-
32
- 1. Fork it ( https://github.com/[my-github-username]/kitchen-pester/fork )
33
- 2. Create your feature branch (`git checkout -b my-new-feature`)
34
- 3. Commit your changes (`git commit -am 'Add some feature'`)
35
- 4. Push to the branch (`git push origin my-new-feature`)
36
- 5. Create a new Pull Request
1
+ [![Gem Version](https://badge.fury.io/rb/kitchen-pester.svg)](http://badge.fury.io/rb/kitchen-pester)
2
+ # Kitchen::Pester
3
+
4
+ Execute [Pester](https://github.com/pester/Pester) tests right from Test-Kitchen, without having to transit the Busser layer.
5
+
6
+ ## Usage
7
+
8
+ Either
9
+ ```
10
+ gem install kitchen-pester
11
+ ```
12
+ or include
13
+ ```
14
+ gem 'kitchen-pester'
15
+ ```
16
+ in your Gemfile.
17
+
18
+ In your .kitchen.yml include
19
+ ```
20
+ verifier:
21
+ name: pester
22
+ ```
23
+ This can be a top-level declaration, a per-node declaration, or a per-suite declaration.
24
+
25
+ ### Options
26
+
27
+ * `restart_winrm` - boolean, default is false. This is primarily to support powershell v2 scenarios. If Pester is not being found, enable this option.
28
+ * `test_folder` - string, default is nil. `test-folder` allows you to specify a custom path (the default is ./test/integration/) for your integration tests. This can be an absolute path or relative to the root of the folder kitchen is running from. This path must exist.
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it ( https://github.com/[my-github-username]/kitchen-pester/fork )
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create a new Pull Request
data/Rakefile CHANGED
@@ -1,52 +1,52 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require "bundler/gem_tasks"
4
-
5
- require "rake/testtask"
6
- Rake::TestTask.new(:unit) do |t|
7
- t.libs.push "lib"
8
- t.test_files = FileList["spec/**/*_spec.rb"]
9
- t.verbose = true
10
- end
11
-
12
- desc "Run all test suites"
13
- task :test => [:unit]
14
-
15
- desc "Display LOC stats"
16
- task :stats do
17
- puts "\n## Production Code Stats"
18
- sh "countloc -r lib"
19
- puts "\n## Test Code Stats"
20
- sh "countloc -r spec"
21
- end
22
-
23
- require "finstyle"
24
- require "rubocop/rake_task"
25
- RuboCop::RakeTask.new(:style) do |task|
26
- task.options << "--display-cop-names"
27
- task.options << "--lint"
28
- task.options << '--config' << '.rubocop.yml'
29
- task.patterns = ['lib/**/*.rb']
30
- end
31
-
32
- require "cane/rake_task"
33
- desc "Run cane to check quality metrics"
34
- Cane::RakeTask.new do |cane|
35
- cane.canefile = "./.cane"
36
- end
37
-
38
- desc "Run all quality tasks"
39
- task :quality => [:cane, :style, :stats]
40
-
41
- require "yard"
42
- YARD::Rake::YardocTask.new
43
-
44
- desc "Generate gem dependency graph"
45
- task :viz do
46
- Bundler.with_clean_env do
47
- sh "bundle viz --without test development guard " \
48
- "--requirements --version"
49
- end
50
- end
51
-
52
- task :default => [:test, :quality]
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rake/testtask"
6
+ Rake::TestTask.new(:unit) do |t|
7
+ t.libs.push "lib"
8
+ t.test_files = FileList["spec/**/*_spec.rb"]
9
+ t.verbose = true
10
+ end
11
+
12
+ desc "Run all test suites"
13
+ task :test => [:unit]
14
+
15
+ desc "Display LOC stats"
16
+ task :stats do
17
+ puts "\n## Production Code Stats"
18
+ sh "countloc -r lib"
19
+ puts "\n## Test Code Stats"
20
+ sh "countloc -r spec"
21
+ end
22
+
23
+ require "finstyle"
24
+ require "rubocop/rake_task"
25
+ RuboCop::RakeTask.new(:style) do |task|
26
+ task.options << "--display-cop-names"
27
+ task.options << "--lint"
28
+ task.options << '--config' << '.rubocop.yml'
29
+ task.patterns = ['lib/**/*.rb']
30
+ end
31
+
32
+ require "cane/rake_task"
33
+ desc "Run cane to check quality metrics"
34
+ Cane::RakeTask.new do |cane|
35
+ cane.canefile = "./.cane"
36
+ end
37
+
38
+ desc "Run all quality tasks"
39
+ task :quality => [:cane, :style, :stats]
40
+
41
+ require "yard"
42
+ YARD::Rake::YardocTask.new
43
+
44
+ desc "Generate gem dependency graph"
45
+ task :viz do
46
+ Bundler.with_clean_env do
47
+ sh "bundle viz --without test development guard " \
48
+ "--requirements --version"
49
+ end
50
+ end
51
+
52
+ task :default => [:test, :quality]
@@ -1,27 +1,27 @@
1
- # encoding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
- require 'kitchen/verifier/pester_version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = "kitchen-pester"
9
- spec.version = Kitchen::Verifier::PESTER_VERSION
10
- spec.authors = ["Steven Murawski"]
11
- spec.email = ["steven.murawski@gmail.com"]
12
- spec.summary = 'Test-Kitchen verifier for Pester.'
13
- spec.description = 'Skip all that Busser stuff and jump right into Pester.'
14
- spec.homepage = "https://github.com/test-kitchen/kitchen-pester"
15
- spec.license = "Apache 2"
16
-
17
- spec.files = `git ls-files -z`.split("\x0")
18
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
- spec.require_paths = ["lib"]
21
-
22
- spec.add_development_dependency "bundler", "~> 1.7"
23
- spec.add_development_dependency "rake", "~> 10.0"
24
- spec.add_development_dependency "pry", "~> 0.10"
25
-
26
- spec.add_dependency "test-kitchen", "~> 1.4"
27
- end
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'kitchen/verifier/pester_version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "kitchen-pester"
9
+ spec.version = Kitchen::Verifier::PESTER_VERSION
10
+ spec.authors = ["Steven Murawski"]
11
+ spec.email = ["steven.murawski@gmail.com"]
12
+ spec.summary = 'Test-Kitchen verifier for Pester.'
13
+ spec.description = 'Skip all that Busser stuff and jump right into Pester.'
14
+ spec.homepage = "https://github.com/test-kitchen/kitchen-pester"
15
+ spec.license = "Apache 2"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "pry", "~> 0.10"
25
+
26
+ spec.add_dependency "test-kitchen", "~> 1.4"
27
+ end
@@ -1,197 +1,310 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Steven Murawski (<steven.murawski@gmail.com>)
4
- #
5
- # Copyright (C) 2015, Steven Murawski
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require 'pathname'
20
- require 'kitchen/verifier/base'
21
- require 'kitchen/verifier/pester_version'
22
-
23
- module Kitchen
24
-
25
- module Verifier
26
-
27
- class Pester < Kitchen::Verifier::Base
28
-
29
- kitchen_verifier_api_version 1
30
-
31
- plugin_version Kitchen::Verifier::PESTER_VERSION
32
-
33
- default_config :restart_winrm, false
34
- default_config :test_folder
35
-
36
- # Creates a new Verifier object using the provided configuration data
37
- # which will be merged with any default configuration.
38
- #
39
- # @param config [Hash] provided verifier configuration
40
- def initialize(config = {})
41
- init_config(config)
42
- end
43
-
44
- # Creates a temporary directory on the local workstation into which
45
- # verifier related files and directories can be copied or created. The
46
- # contents of this directory will be copied over to the instance before
47
- # invoking the verifier's run command. After this method completes, it
48
- # is expected that the contents of the sandbox is complete and ready for
49
- # copy to the remote instance.
50
- #
51
- # **Note:** any subclasses would be well advised to call super first when
52
- # overriding this method, for example:
53
- #
54
- # @example overriding `#create_sandbox`
55
- #
56
- # class MyVerifier < Kitchen::Verifier::Base
57
- # def create_sandbox
58
- # super
59
- # # any further file copies, preparations, etc.
60
- # end
61
- # end
62
- def create_sandbox
63
- super
64
- prepare_pester_tests
65
- end
66
-
67
- # Generates a command string which will install and configure the
68
- # verifier software on an instance. If no work is required, then `nil`
69
- # will be returned.
70
- #
71
- # @return [String] a command string
72
- def install_command
73
- return if local_suite_files.empty?
74
-
75
- cmd = <<-CMD
76
- set-executionpolicy unrestricted -force
77
- if (-not (get-module -list pester)) {
78
- if (get-module -list PowerShellGet){
79
- import-module PowerShellGet -force
80
- import-module PackageManagement -force
81
- get-packageprovider -name NuGet -force | out-null
82
- install-module Pester -force
83
- }
84
- else {
85
- if (-not (get-module -list PsGet)){
86
- iex (new-object Net.WebClient).DownloadString('http://bit.ly/GetPsGet')
87
- }
88
- import-module psget -force
89
- Install-Module Pester
90
- }
91
- }
92
- CMD
93
- wrap_shell_code(Util.outdent!(cmd))
94
- end
95
-
96
- # Generates a command string which will perform any data initialization
97
- # or configuration required after the verifier software is installed
98
- # but before the sandbox has been transferred to the instance. If no work
99
- # is required, then `nil` will be returned.
100
- #
101
- # @return [String] a command string
102
- def init_command
103
- restart_winrm_service if config[:restart_winrm]
104
- end
105
-
106
- # Generates a command string which will perform any commands or
107
- # configuration required just before the main verifier run command but
108
- # after the sandbox has been transferred to the instance. If no work is
109
- # required, then `nil` will be returned.
110
- #
111
- # @return [String] a command string
112
- def prepare_command
113
- end
114
-
115
- # Generates a command string which will invoke the main verifier
116
- # command on the prepared instance. If no work is required, then `nil`
117
- # will be returned.
118
- #
119
- # @return [String] a command string
120
- def run_command
121
- return if local_suite_files.empty?
122
- wrap_shell_code(Util.outdent!(<<-CMD
123
- $global:ProgressPreference = 'SilentlyContinue'
124
- $TestPath = "#{File.join(config[:root_path], 'suites')}"
125
- import-module Pester -force; invoke-pester -path $testpath -enableexit
126
- CMD
127
- ))
128
- end
129
-
130
- #private
131
-
132
- def restart_winrm_service
133
-
134
- cmd = 'schtasks /Create /TN restart_winrm /TR ' \
135
- '"powershell -command restart-service winrm" ' \
136
- '/SC ONCE /ST 00:00 '
137
- wrap_shell_code(Util.outdent!(<<-CMD
138
- #{cmd}
139
- schtasks /RUN /TN restart_winrm
140
- CMD
141
- ))
142
- end
143
-
144
- # Returns an Array of test suite filenames for the related suite currently
145
- # residing on the local workstation. Any special provisioner-specific
146
- # directories (such as a Chef roles/ directory) are excluded.
147
- #
148
- # @return [Array<String>] array of suite files
149
- # @api private
150
-
151
- def local_suite_files
152
- base = File.join(test_folder, config[:suite_name])
153
- top_level_glob = File.join(base, "*")
154
- folder_glob = File.join(base, "*/**/*")
155
- top = Dir.glob(top_level_glob)
156
- nested = Dir.glob(folder_glob)
157
- (top << nested).flatten!.reject do |f|
158
- File.directory?(f)
159
- end
160
- end
161
-
162
- # Copies all test suite files into the suites directory in the sandbox.
163
- #
164
- # @api private
165
- def prepare_pester_tests
166
- base = File.join(test_folder, config[:suite_name])
167
- info("Preparing to copy files from #{base} to the SUT.")
168
-
169
- local_suite_files.each do |src|
170
- dest = File.join(sandbox_suites_dir, src.sub("#{base}/", ""))
171
- debug("Copying #{src} to #{dest}")
172
- FileUtils.mkdir_p(File.dirname(dest))
173
- FileUtils.cp(src, dest, preserve: true)
174
- end
175
- end
176
-
177
- # @return [String] path to suites directory under sandbox path
178
- # @api private
179
- def sandbox_suites_dir
180
- File.join(sandbox_path, "suites")
181
- end
182
-
183
- def test_folder
184
- return config[:test_base_path] if config[:test_folder].nil?
185
- absolute_test_folder
186
- end
187
-
188
- def absolute_test_folder
189
- path = (Pathname.new config[:test_folder]).realpath
190
- integration_path = File.join(path, 'integration')
191
- return path unless Dir.exist?(integration_path)
192
- integration_path
193
- end
194
-
195
- end
196
- end
197
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Steven Murawski (<steven.murawski@gmail.com>)
4
+ #
5
+ # Copyright (C) 2015, Steven Murawski
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'pathname'
20
+ require 'kitchen/verifier/base'
21
+ require 'kitchen/verifier/pester_version'
22
+
23
+ module Kitchen
24
+
25
+ module Verifier
26
+
27
+ class Pester < Kitchen::Verifier::Base
28
+
29
+ kitchen_verifier_api_version 1
30
+
31
+ plugin_version Kitchen::Verifier::PESTER_VERSION
32
+
33
+ default_config :restart_winrm, false
34
+ default_config :test_folder
35
+ default_config :run_as_scheduled_task, false
36
+ default_config :use_local_pester_module, false
37
+
38
+ # Creates a new Verifier object using the provided configuration data
39
+ # which will be merged with any default configuration.
40
+ #
41
+ # @param config [Hash] provided verifier configuration
42
+ def initialize(config = {})
43
+ init_config(config)
44
+ end
45
+
46
+ # Creates a temporary directory on the local workstation into which
47
+ # verifier related files and directories can be copied or created. The
48
+ # contents of this directory will be copied over to the instance before
49
+ # invoking the verifier's run command. After this method completes, it
50
+ # is expected that the contents of the sandbox is complete and ready for
51
+ # copy to the remote instance.
52
+ #
53
+ # **Note:** any subclasses would be well advised to call super first when
54
+ # overriding this method, for example:
55
+ #
56
+ # @example overriding `#create_sandbox`
57
+ #
58
+ # class MyVerifier < Kitchen::Verifier::Base
59
+ # def create_sandbox
60
+ # super
61
+ # # any further file copies, preparations, etc.
62
+ # end
63
+ # end
64
+ def create_sandbox
65
+ super
66
+ prepare_powershell_modules
67
+ prepare_pester_tests
68
+ end
69
+
70
+ # Generates a command string which will install and configure the
71
+ # verifier software on an instance. If no work is required, then `nil`
72
+ # will be returned.
73
+ #
74
+ # @return [String] a command string
75
+ def install_command
76
+ return if local_suite_files.empty?
77
+ return if config[:use_local_pester_module]
78
+
79
+ really_wrap_shell_code(install_command_script)
80
+ end
81
+
82
+ # Generates a command string which will perform any data initialization
83
+ # or configuration required after the verifier software is installed
84
+ # but before the sandbox has been transferred to the instance. If no work
85
+ # is required, then `nil` will be returned.
86
+ #
87
+ # @return [String] a command string
88
+ def init_command
89
+ restart_winrm_service if config[:restart_winrm]
90
+ end
91
+
92
+ # Generates a command string which will perform any commands or
93
+ # configuration required just before the main verifier run command but
94
+ # after the sandbox has been transferred to the instance. If no work is
95
+ # required, then `nil` will be returned.
96
+ #
97
+ # @return [String] a command string
98
+ def prepare_command
99
+ end
100
+
101
+ # Generates a command string which will invoke the main verifier
102
+ # command on the prepared instance. If no work is required, then `nil`
103
+ # will be returned.
104
+ #
105
+ # @return [String] a command string
106
+ def run_command
107
+ return if local_suite_files.empty?
108
+
109
+ cmd = if config[:run_as_scheduled_task]
110
+ wrap_scheduled_task('verify-run', run_command_script)
111
+ else
112
+ run_command_script
113
+ end
114
+
115
+ really_wrap_shell_code(cmd)
116
+ end
117
+
118
+ #private
119
+ def run_command_script
120
+ <<-CMD
121
+ $TestPath = "#{File.join(config[:root_path], 'pester')}";
122
+ import-module Pester -force;
123
+ $result = invoke-pester -path $testpath -passthru ;
124
+ $result |
125
+ export-clixml (join-path $testpath 'result.xml');
126
+ $host.setshouldexit($result.failedcount)
127
+ CMD
128
+ end
129
+
130
+ def really_wrap_shell_code(code)
131
+ wrap_shell_code(Util.outdent!(use_local_powershell_modules(code)))
132
+ end
133
+
134
+ def use_local_powershell_modules(script)
135
+ <<-EOH
136
+ set-executionpolicy unrestricted -force;
137
+ $global:ProgressPreference = 'SilentlyContinue'
138
+ #{"$VerbosePreference = 'Continue'" if instance.logger.logdev.level == 0}
139
+ $env:psmodulepath += ";$(join-path (resolve-path $env:temp).path 'verifier/modules')";
140
+ # $env:psmodulepath -split ';' | % {write-output "PSModulePath contains:"} {write-output "`t$_"}
141
+ #{script}
142
+ EOH
143
+ end
144
+
145
+ def random_string
146
+ (0...8).map { (65 + rand(26)).chr }.join
147
+ end
148
+
149
+ def wrap_scheduled_task (name, script)
150
+ randomized_name = "#{name}-#{random_string}"
151
+ <<-EOH
152
+ import-module NamedPipes, ScheduledTaskRunner, PesterUtil
153
+ $Action = @'
154
+ #{script}
155
+ '@
156
+ $ScriptBlock = [scriptblock]::Create($action)
157
+ Add-ScheduledTaskCommand -name #{randomized_name} -Action $ScriptBlock
158
+ Invoke-ScheduledTaskCommand -name #{randomized_name}
159
+ $ExitCode = Get-ScheduledTaskExitCode -name #{randomized_name}
160
+ Remove-ScheduledTaskCommand -name #{randomized_name}
161
+ $TestResultPath = "#{File.join(config[:root_path], 'pester/result.xml')}"
162
+ $TestResults = import-clixml $TestResultPath
163
+ Write-Host
164
+ ConvertFrom-PesterOutputObject $TestResults
165
+ Write-Host
166
+ $host.SetShouldExit($ExitCode)
167
+ EOH
168
+ end
169
+
170
+ def install_command_script
171
+ <<-EOH
172
+ function directory($path){
173
+ if (test-path $path) {(resolve-path $path).providerpath}
174
+ else {(resolve-path (mkdir $path)).providerpath}
175
+ }
176
+ $VerifierModulePath = directory $env:temp/verifier/modules
177
+ $VerifierTestsPath = directory $env:temp/verifier/pester
178
+
179
+ function test-module($module){
180
+ (get-module $module -list) -ne $null
181
+ }
182
+ if (-not (test-module pester)) {
183
+ if (test-module PowerShellGet){
184
+ import-module PowerShellGet -force
185
+ import-module PackageManagement -force
186
+ get-packageprovider -name NuGet -force | out-null
187
+ install-module Pester -force
188
+ }
189
+ else {
190
+ if (-not (test-module PsGet)){
191
+ iex (new-object Net.WebClient).DownloadString('http://bit.ly/GetPsGet')
192
+ }
193
+ try {
194
+ import-module psget -force -erroraction stop
195
+ Install-Module Pester
196
+ }
197
+ catch {
198
+ Write-Output "Installing from Github"
199
+ $zipfile = join-path(resolve-path "$env:temp/verifier") "pester.zip"
200
+ if (-not (test-path $zipfile)){
201
+ $source = 'https://github.com/pester/Pester/archive/3.3.14.zip'
202
+ [byte[]]$bytes = (new-object System.net.WebClient).DownloadData($source)
203
+ [IO.File]::WriteAllBytes($zipfile, $bytes)
204
+ $bytes = $null
205
+ [gc]::collect()
206
+ write-output "Downloaded Pester.zip"
207
+ }
208
+ write-output "Creating Shell.Application COM object"
209
+ $shellcom = new-object -com shell.application
210
+ Write-Output "Creating COM object for zip file."
211
+ $zipcomobject = $shellcom.namespace($zipfile)
212
+ Write-Output "Creating COM object for module destination."
213
+ $destination = $shellcom.namespace($VerifierModulePath)
214
+ Write-Output "Unpacking zip file."
215
+ $destination.CopyHere($zipcomobject.Items(), 0x610)
216
+ rename-item (join-path $VerifierModulePath "Pester-3.3.14") -newname 'Pester' -force
217
+ }
218
+ }
219
+ }
220
+ if (-not (test-module Pester)) {
221
+ throw "Unable to install Pester. Please include Pester in your base image or install during your converge."
222
+ }
223
+ EOH
224
+ end
225
+
226
+ def restart_winrm_service
227
+
228
+ cmd = 'schtasks /Create /TN restart_winrm /TR ' \
229
+ '"powershell -command restart-service winrm" ' \
230
+ '/SC ONCE /ST 00:00 '
231
+ wrap_shell_code(Util.outdent!(<<-CMD
232
+ #{cmd}
233
+ schtasks /RUN /TN restart_winrm
234
+ CMD
235
+ ))
236
+ end
237
+
238
+ # Returns an Array of test suite filenames for the related suite currently
239
+ # residing on the local workstation. Any special provisioner-specific
240
+ # directories (such as a Chef roles/ directory) are excluded.
241
+ #
242
+ # @return [Array<String>] array of suite files
243
+ # @api private
244
+
245
+ def suite_test_folder
246
+ @suite_test_folder ||= File.join(test_folder, config[:suite_name])
247
+ end
248
+
249
+ def suite_level_glob
250
+ Dir.glob(File.join(suite_test_folder, "*"))
251
+ end
252
+
253
+ def suite_verifier_level_glob
254
+ Dir.glob(File.join(suite_test_folder, "*/**/*"))
255
+ end
256
+
257
+ def local_suite_files
258
+ suite = suite_level_glob
259
+ suite_verifier = suite_verifier_level_glob
260
+ (suite << suite_verifier).flatten!.reject do |f|
261
+ File.directory?(f)
262
+ end
263
+ end
264
+
265
+ def sandboxify_path(path)
266
+ File.join(sandbox_path, path.sub("#{suite_test_folder}/", ""))
267
+ end
268
+
269
+ # Copies all test suite files into the suites directory in the sandbox.
270
+ #
271
+ # @api private
272
+ def prepare_pester_tests
273
+ info("Preparing to copy files from #{suite_test_folder} to the SUT.")
274
+
275
+ local_suite_files.each do |src|
276
+ dest = sandboxify_path(src)
277
+ debug("Copying #{src} to #{dest}")
278
+ FileUtils.mkdir_p(File.dirname(dest))
279
+ FileUtils.cp(src, dest, preserve: true)
280
+ end
281
+ end
282
+
283
+ def prepare_powershell_module(name)
284
+ FileUtils.mkdir_p(File.join(sandbox_path, "modules/#{name}"))
285
+ FileUtils.cp(File.join(File.dirname(__FILE__), "../../support/powershell/#{name}/#{name}.psm1"), File.join(sandbox_path, "modules/#{name}/#{name}.psm1"), preserve: true)
286
+ end
287
+
288
+ def prepare_powershell_modules
289
+ info("Preparing to copy supporting powershell modules.")
290
+ %w[NamedPipes ScheduledTaskRunner PesterUtil].each do |module_name|
291
+ prepare_powershell_module module_name
292
+ end
293
+
294
+ end
295
+
296
+ def test_folder
297
+ return config[:test_base_path] if config[:test_folder].nil?
298
+ absolute_test_folder
299
+ end
300
+
301
+ def absolute_test_folder
302
+ path = (Pathname.new config[:test_folder]).realpath
303
+ integration_path = File.join(path, 'integration')
304
+ return path unless Dir.exist?(integration_path)
305
+ integration_path
306
+ end
307
+
308
+ end
309
+ end
310
+ end
@@ -1,5 +1,5 @@
1
- module Kitchen
2
- module Verifier
3
- PESTER_VERSION = '0.5.0'
4
- end
1
+ module Kitchen
2
+ module Verifier
3
+ PESTER_VERSION = '0.7.0'
4
+ end
5
5
  end
@@ -0,0 +1,134 @@
1
+ Add-Type -AssemblyName System.Core;
2
+
3
+ $script:NamedPipes = @()
4
+
5
+ function New-NamedPipe {
6
+ param (
7
+ [parameter(Mandatory=$true)]
8
+ [ValidateSet('In', 'Out')]
9
+ [string]
10
+ $Direction,
11
+ [parameter(Mandatory=$true)]
12
+ [ValidateSet('Client', 'Server')]
13
+ [string]
14
+ $Role,
15
+ [parameter(Mandatory=$true)]
16
+ [ValidateNotNullOrEmpty()]
17
+ [string]
18
+ $Name,
19
+ [switch]
20
+ $Quiet
21
+ )
22
+ try {
23
+ $pipeReader = $null
24
+ $pipeWriter = $null
25
+
26
+ if ($Role -like 'Server') {
27
+ $pipe = new-object -ErrorAction Stop System.IO.Pipes.NamedPipeServerStream($Name,
28
+ [System.IO.Pipes.PipeDirection]::$Direction)
29
+ }
30
+ else {
31
+ $pipe = new-object -ErrorAction Stop System.IO.Pipes.NamedPipeClientStream($env:ComputerName,
32
+ $Name, [System.IO.Pipes.PipeDirection]::$Direction)
33
+ }
34
+ if ($Direction -like 'In') {
35
+ $pipeReader = new-object System.IO.StreamReader($pipe)
36
+ }
37
+ else {
38
+ $pipeWriter = new-object System.IO.StreamWriter($pipe)
39
+ }
40
+ $output = new-object PSObject -property @{
41
+ Name = $Name
42
+ NamedPipe = $pipe
43
+ Role = $Role
44
+ Direction = $Direction
45
+ PipeReader = $pipeReader
46
+ PipeWriter = $pipeWriter
47
+ }
48
+ $script:NamedPipes += $output
49
+ if (-not $Quiet) {$output}
50
+ }
51
+ catch {
52
+ throw "Failed to create the named pipe."
53
+ }
54
+ }
55
+
56
+ function Get-NamedPipe {
57
+ param (
58
+ $Name = '*',
59
+ $Role = '*'
60
+ )
61
+ $pipe = $null
62
+ $pipe = $script:NamedPipes |
63
+ where {$_.name -like $Name -and $_.role -like $Role}
64
+ if ($pipe -eq $null) { throw "Unable to find pipe $Name" }
65
+ return $pipe
66
+ }
67
+
68
+ function Start-NamedPipeServer {
69
+ param ($Name)
70
+ $PipeServer = Get-NamedPipe -Name $Name -Role Server
71
+ $PipeServer.NamedPipe.WaitForConnection()
72
+ Write-Host "Named Pipe $Name is connected."
73
+ }
74
+
75
+ function Connect-NamedPipeClient {
76
+ param ($Name)
77
+ $PipeClient = Get-NamedPipe -Name $Name -Role Client
78
+ $PipeClient.NamedPipe.Connect()
79
+ if ($PipeClient.PipeWriter -ne $null) {
80
+ $PipeClient.pipeWriter.AutoFlush = $true
81
+ }
82
+ }
83
+
84
+ function Write-NamedPipe {
85
+ param(
86
+ [parameter(Mandatory = $true)]
87
+ [ValidateNotNullOrEmpty()]
88
+ [string]
89
+ $Name,
90
+ [parameter(ValueFromPipeline=$true)]
91
+ [string]
92
+ $Content)
93
+ begin {
94
+ $Pipe = Get-NamedPipe -Name $Name |
95
+ where {$_.PipeWriter -ne $null}
96
+ }
97
+ process {
98
+ if ($Pipe.NamedPipe.IsConnected){
99
+ $Pipe.PipeWriter.Writeline($Content)
100
+ }
101
+ }
102
+ }
103
+
104
+ function Read-NamedPipe {
105
+ param ($Name)
106
+ $Pipe = Get-NamedPipe -Name $Name | where {$_.PipeReader -ne $null}
107
+ while ($Pipe.NamedPipe.IsConnected) {
108
+ $output = $Pipe.PipeReader.ReadLine()
109
+ if ($output -like "STOP READING $Name") {
110
+ break;
111
+ }
112
+ $output
113
+ }
114
+ }
115
+
116
+ function Send-StopReadingCommand {
117
+ param ($Name)
118
+ Write-NamedPipe -Name $Name -Content "STOP READING $Name"
119
+ }
120
+
121
+ function Remove-NamedPipe {
122
+ param ($name)
123
+ Get-NamedPipe -Name $Name |
124
+ foreach {
125
+ if ($_.Pipewriter -ne $null) {
126
+ $_.PipeWriter.dispose()
127
+ }
128
+ if ($_.Pipereader -ne $null) {
129
+ $_.Pipereader.dispose()
130
+ }
131
+ $_.NamedPipe.dispose()
132
+ }
133
+ $script:NamedPipes = $script:NamedPipes | where {$_.name -notlike $Name}
134
+ }
@@ -0,0 +1,24 @@
1
+ function ConvertFrom-PesterOutputObject {
2
+ param (
3
+ [parameter(ValueFromPipeline=$true)]
4
+ [object]
5
+ $InputObject
6
+ )
7
+ begin {
8
+ $PesterModule = Import-Module Pester -Passthru
9
+ }
10
+ process {
11
+ $DescribeGroup = $InputObject.testresult | Group-Object Describe
12
+ foreach ($DescribeBlock in $DescribeGroup) {
13
+ $PesterModule.Invoke({Write-Screen $args[0]}, "Describing $($DescribeBlock.Name)")
14
+ $ContextGroup = $DescribeBlock.group | Group-Object Context
15
+ foreach ($ContextBlock in $ContextGroup) {
16
+ $PesterModule.Invoke({Write-Screen $args[0]}, "`tContext $($subheader.name)")
17
+ foreach ($TestResult in $ContextBlock.group) {
18
+ $PesterModule.Invoke({Write-PesterResult $args[0]}, $TestResult)
19
+ }
20
+ }
21
+ }
22
+ $PesterModule.Invoke({Write-PesterReport $args[0]}, $InputObject)
23
+ }
24
+ }
@@ -0,0 +1,92 @@
1
+ import-module NamedPipes -force
2
+
3
+ $script:TaskLastExitCode = @{}
4
+
5
+ function Add-ScheduledTaskCommand {
6
+ param ([string]$Name, [scriptblock]$Action)
7
+ $command = @"
8
+ `$env:temp = '$env:temp';
9
+ `$env:psmodulepath = '$env:psmodulepath';
10
+ import-module NamedPipes -force;
11
+
12
+ # Set up named pipe
13
+ start-sleep -seconds 5
14
+
15
+ New-NamedPipe -Role Client -Direction Out -Quiet -Name 'kitchen-$name';
16
+ Connect-NamedPipeClient -Name 'kitchen-$name';
17
+
18
+ # Run the real action and send it down the named pipe
19
+ try {
20
+ `$ActionString = @'
21
+ $($action.ToString())
22
+ '@
23
+
24
+ [scriptblock]::create(`$ActionString).InvokeReturnAsIs() |
25
+ write-NamedPipe -Name 'kitchen-$name'
26
+ }
27
+ catch [Exception] {
28
+ write-NamedPipe -name 'kitchen-$name' -content `$_.exception.message
29
+ Write-NamedPipe -Name 'kitchen-$name' -content `$_.exception.stacktrace
30
+ }
31
+ finally {
32
+ # Close out named pipe
33
+ Send-StopReadingCommand -Name 'kitchen-$name';
34
+ Remove-NamedPipe -Name 'kitchen-$name';
35
+ }
36
+ "@
37
+
38
+ try {
39
+ $ActionWithEnvironment = [scriptblock]::Create($command)
40
+ }
41
+ catch {
42
+ Write-Output "Failed to validate: "
43
+ Write-Output $command
44
+ throw $_.exception
45
+ }
46
+
47
+ $ActionWithEnvironment.ToString() | Out-file "$env:temp/$Name.ps1"
48
+ if (test-path "$env:temp/$name.ps1") {
49
+ schtasks /create /tn "kitchen-$name" /ru System /sc daily /st 00:00 /rl HIGHEST /f /tr "powershell -noprofile -executionpolicy unrestricted -file $env:temp/$name.ps1" | Out-Null
50
+ Write-Host "`tCreated Scheduled Task $Name."
51
+ }
52
+ else {
53
+ throw "failed to create scheduled task command."
54
+ }
55
+ }
56
+
57
+ function Remove-ScheduledTaskCommand {
58
+ param ([string]$Name)
59
+ schtasks /delete /tn "kitchen-$name" /f | Out-Null
60
+ Write-Host "`tDeleted Scheduld Task $Name."
61
+ }
62
+
63
+ function Get-ScheduledTaskExitCode {
64
+ param ([string]$Name)
65
+ (Get-ScheduledTaskStatus -name $name).'Last Result' |
66
+ where {-not [string]::IsNullOrEmpty($_)} |
67
+ foreach {[int]::Parse($_.trim())}
68
+ }
69
+
70
+ function Get-ScheduledTaskStatus {
71
+ param ([string]$Name)
72
+ $task = schtasks /query /tn "kitchen-$name" /fo csv /v |
73
+ ConvertFrom-Csv
74
+ $task
75
+ }
76
+
77
+ function Invoke-ScheduledTaskCommand {
78
+ param ([string]$Name)
79
+ try {
80
+ new-namedpipe -Role Server -Direction In -Quiet -Name "kitchen-$name"
81
+ schtasks /run /tn "kitchen-$name" | Out-Null
82
+ Write-Host "`tRunning Scheduled Task $Name."
83
+ Start-NamedPipeServer -Name "kitchen-$name"
84
+ Read-NamedPipe -Name "kitchen-$name"
85
+ }
86
+ finally {
87
+ Remove-NamedPipe -name "kitchen-$name"
88
+ while ((Get-ScheduledTaskStatus -name $name).Status -notlike 'Ready') {
89
+ start-sleep -seconds 1
90
+ }
91
+ }
92
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-pester
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Murawski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-09 00:00:00.000000000 Z
11
+ date: 2016-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,6 +81,9 @@ files:
81
81
  - kitchen-pester.gemspec
82
82
  - lib/kitchen/verifier/pester.rb
83
83
  - lib/kitchen/verifier/pester_version.rb
84
+ - lib/support/powershell/NamedPipes/NamedPipes.psm1
85
+ - lib/support/powershell/PesterUtil/PesterUtil.psm1
86
+ - lib/support/powershell/ScheduledTaskRunner/ScheduledTaskRunner.psm1
84
87
  homepage: https://github.com/test-kitchen/kitchen-pester
85
88
  licenses:
86
89
  - Apache 2