test-kitchen 1.23.3 → 1.23.4
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.
- checksums.yaml +4 -4
- data/lib/kitchen/version.rb +1 -1
- data/support/chef-client-zero.rb +1 -1
- metadata +5 -324
- data/.gitattributes +0 -3
- data/.github/ISSUE_TEMPLATE.md +0 -56
- data/.github/lock.yml +0 -1
- data/.gitignore +0 -38
- data/.gitmodules +0 -0
- data/.kitchen.appveyor.yml +0 -25
- data/.kitchen.dokken.yml +0 -31
- data/.kitchen.proxy.yml +0 -27
- data/.rubocop.yml +0 -5
- data/.travis.yml +0 -57
- data/.yardopts +0 -3
- data/Berksfile +0 -3
- data/CHANGELOG.md +0 -1510
- data/CONTRIBUTING.md +0 -14
- data/ECOSYSTEM.md +0 -93
- data/Gemfile +0 -40
- data/Gemfile.proxy_tests +0 -4
- data/Guardfile +0 -42
- data/MAINTAINERS.md +0 -29
- data/README.md +0 -138
- data/RELEASE_NOTES.md +0 -167
- data/Rakefile +0 -77
- data/appveyor.yml +0 -47
- data/docs/CONTRIBUTING.md +0 -8
- data/docs/LICENSE +0 -22
- data/docs/README.md +0 -78
- data/docs/archetypes/default.md +0 -6
- data/docs/config.toml +0 -36
- data/docs/content/docs/_index.md +0 -5
- data/docs/content/docs/drivers/_index.md +0 -27
- data/docs/content/docs/drivers/azurerm.md +0 -44
- data/docs/content/docs/drivers/vagrant.md +0 -39
- data/docs/content/docs/getting-started/00-introduction.md +0 -14
- data/docs/content/docs/getting-started/01-installing.md +0 -64
- data/docs/content/docs/getting-started/02-getting-help.md +0 -59
- data/docs/content/docs/getting-started/03-creating-cookbook.md +0 -46
- data/docs/content/docs/getting-started/04-kitchen-yml.md +0 -56
- data/docs/content/docs/getting-started/05-instances.md +0 -79
- data/docs/content/docs/getting-started/06-writing-recipe.md +0 -21
- data/docs/content/docs/getting-started/07-running-converge.md +0 -134
- data/docs/content/docs/getting-started/08-manually-verifying.md +0 -55
- data/docs/content/docs/getting-started/09-writing-test.md +0 -49
- data/docs/content/docs/getting-started/10-running-verify.md +0 -120
- data/docs/content/docs/getting-started/11-running-test.md +0 -168
- data/docs/content/docs/getting-started/12-adding-platform.md +0 -206
- data/docs/content/docs/getting-started/13-adding-feature.md +0 -30
- data/docs/content/docs/getting-started/14-adding-suite.md +0 -60
- data/docs/content/docs/getting-started/15-adding-test.md +0 -66
- data/docs/content/docs/getting-started/16-adding-recipe.md +0 -53
- data/docs/content/docs/getting-started/17-excluding-platforms.md +0 -101
- data/docs/content/docs/getting-started/18-next-steps.md +0 -23
- data/docs/content/docs/getting-started/_index.md +0 -5
- data/docs/content/docs/provisioners/_index.md +0 -36
- data/docs/content/docs/provisioners/chef.md +0 -69
- data/docs/content/docs/provisioners/shell.md +0 -31
- data/docs/content/docs/reference/_index.md +0 -5
- data/docs/content/docs/reference/configuration.md +0 -53
- data/docs/content/docs/reference/examples.md +0 -97
- data/docs/content/docs/reference/faq.md +0 -58
- data/docs/content/docs/reference/fixtures.md +0 -32
- data/docs/content/docs/reference/glossary.md +0 -34
- data/docs/content/docs/reference/lifecycle-hooks.md +0 -68
- data/docs/content/docs/reference/reboots.md +0 -24
- data/docs/content/docs/verifiers/_index.md +0 -14
- data/docs/content/docs/verifiers/inspec.md +0 -44
- data/docs/content/docs/verifiers/serverspec.md +0 -20
- data/docs/static/images/chef-logo.png +0 -0
- data/docs/static/images/chef-logo.svg +0 -1
- data/docs/static/images/github-banner.png +0 -0
- data/docs/static/images/github-banner.svg +0 -71
- data/docs/static/images/kitchen-logo.png +0 -0
- data/docs/static/images/logo-block.svg +0 -222
- data/docs/static/images/logo.png +0 -0
- data/docs/static/images/logos-group.png +0 -0
- data/docs/static/images/terminal-1.png +0 -0
- data/docs/static/images/terminal-1.svg +0 -589
- data/docs/static/images/terminal-2.png +0 -0
- data/docs/static/images/terminal-2.svg +0 -235
- data/docs/static/images/terminal-3.png +0 -0
- data/docs/static/images/terminal-3.svg +0 -439
- data/docs/static/index.html +0 -59
- data/docs/static/javascripts/all.js +0 -348
- data/docs/static/javascripts/vendor/foundation.min.js +0 -4
- data/docs/static/javascripts/vendor/jquery.min.js +0 -5
- data/docs/static/javascripts/vendor/what-input.js +0 -336
- data/docs/static/stylesheets/site.css +0 -4667
- data/docs/themes/kitchen/layouts/_default/baseof.html +0 -53
- data/docs/themes/kitchen/layouts/_default/list.html +0 -4
- data/docs/themes/kitchen/layouts/_default/redirect.html +0 -10
- data/docs/themes/kitchen/layouts/_default/single.html +0 -6
- data/docs/themes/kitchen/layouts/partials/core/head.html +0 -6
- data/docs/themes/kitchen/layouts/partials/kitchen/footer.html +0 -18
- data/docs/themes/kitchen/layouts/partials/kitchen/head.html +0 -4
- data/docs/themes/kitchen/layouts/partials/kitchen/header.html +0 -26
- data/docs/themes/kitchen/layouts/partials/search-docs.html +0 -3
- data/docs/themes/kitchen/layouts/partials/sidebar.html +0 -33
- data/docs/themes/kitchen/layouts/shortcodes/button.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/codeblock.html +0 -8
- data/docs/themes/kitchen/layouts/shortcodes/cta.html +0 -5
- data/docs/themes/kitchen/layouts/shortcodes/danger.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/example_fqdn.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/info.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/ol-styled.html +0 -3
- data/docs/themes/kitchen/layouts/shortcodes/success.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/tip.html +0 -1
- data/docs/themes/kitchen/layouts/shortcodes/warning.html +0 -1
- data/docs/themes/kitchen/static/css/kitchen.css +0 -10
- data/docs/themes/kitchen/static/css/kitchen.css.map +0 -7
- data/docs/themes/kitchen/static/fonts/Muli-Bold.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/Muli-Regular.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/Muli-SemiBold.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-brands-400.eot +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-brands-400.svg +0 -1104
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-brands-400.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-brands-400.woff +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-brands-400.woff2 +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-regular-400.eot +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-regular-400.svg +0 -372
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-regular-400.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-regular-400.woff +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-regular-400.woff2 +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-solid-900.eot +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-solid-900.svg +0 -1896
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-solid-900.ttf +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-solid-900.woff +0 -0
- data/docs/themes/kitchen/static/fonts/fontawesome/fa-solid-900.woff2 +0 -0
- data/docs/themes/kitchen/static/images/chef-logo-light.svg +0 -36
- data/docs/themes/kitchen/static/images/chef-logo-white.svg +0 -38
- data/docs/themes/kitchen/static/images/chef-logo.svg +0 -37
- data/docs/themes/kitchen/static/images/favicon.ico +0 -0
- data/docs/themes/kitchen/static/js/scripts-all.js +0 -7
- data/docs/themes/kitchen/static/js/source/chef-hugo.js +0 -116
- data/docs/themes/kitchen/static/js/source/omnitruck.js +0 -82
- data/docs/themes/kitchen/static/js/source/segment.js +0 -52
- data/docs/themes/kitchen/static/sass/_buttons.scss +0 -161
- data/docs/themes/kitchen/static/sass/_core.scss +0 -24
- data/docs/themes/kitchen/static/sass/_forms.scss +0 -14
- data/docs/themes/kitchen/static/sass/_mixins.scss +0 -133
- data/docs/themes/kitchen/static/sass/_typography.scss +0 -34
- data/docs/themes/kitchen/static/sass/_variables.scss +0 -82
- data/docs/themes/kitchen/static/sass/kitchen.scss +0 -7
- data/docs/themes/kitchen/static/sass/kitchen/_footer.scss +0 -50
- data/docs/themes/kitchen/static/sass/kitchen/_header.scss +0 -187
- data/docs/themes/kitchen/static/sass/kitchen/_homepage.scss +0 -27
- data/docs/themes/kitchen/static/sass/kitchen/_utility-bar.scss +0 -173
- data/docs/themes/kitchen/static/sass/partials/_alerts.scss +0 -32
- data/docs/themes/kitchen/static/sass/partials/_bg.scss +0 -19
- data/docs/themes/kitchen/static/sass/partials/_blurbs.scss +0 -25
- data/docs/themes/kitchen/static/sass/partials/_callout.scss +0 -15
- data/docs/themes/kitchen/static/sass/partials/_cards.scss +0 -54
- data/docs/themes/kitchen/static/sass/partials/_dropdown.scss +0 -77
- data/docs/themes/kitchen/static/sass/partials/_grid.scss +0 -87
- data/docs/themes/kitchen/static/sass/partials/_padding.scss +0 -73
- data/docs/themes/kitchen/static/sass/partials/_sidebar.scss +0 -71
- data/docs/themes/kitchen/static/sass/partials/_tabs.scss +0 -125
- data/docs/themes/kitchen/static/sass/typography/_chroma.scss +0 -366
- data/docs/themes/kitchen/static/sass/typography/_code.scss +0 -72
- data/docs/themes/kitchen/static/sass/typography/_headers.scss +0 -90
- data/docs/themes/kitchen/static/sass/typography/_links.scss +0 -127
- data/docs/themes/kitchen/static/sass/typography/_lists.scss +0 -155
- data/docs/themes/kitchen/static/sass/typography/_prose.scss +0 -29
- data/docs/themes/kitchen/static/sass/typography/_text.scss +0 -221
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_animated.scss +0 -20
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_bordered-pulled.scss +0 -20
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_core.scss +0 -16
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_fixed-width.scss +0 -6
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_icons.scss +0 -992
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_larger.scss +0 -23
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_list.scss +0 -18
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_mixins.scss +0 -57
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_rotated-flipped.scss +0 -23
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_screen-reader.scss +0 -5
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_stacked.scss +0 -31
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/_variables.scss +0 -1005
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/fa-brands.scss +0 -21
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/fa-regular.scss +0 -22
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/fa-solid.scss +0 -23
- data/docs/themes/kitchen/static/sass/vendor/fontawesome/fontawesome.scss +0 -16
- data/docs/themes/kitchen/theme.toml +0 -8
- data/features/kitchen_action_commands.feature +0 -164
- data/features/kitchen_command.feature +0 -16
- data/features/kitchen_console_command.feature +0 -35
- data/features/kitchen_defaults.feature +0 -38
- data/features/kitchen_diagnose_command.feature +0 -96
- data/features/kitchen_help_command.feature +0 -16
- data/features/kitchen_init_command.feature +0 -254
- data/features/kitchen_list_command.feature +0 -140
- data/features/kitchen_login_command.feature +0 -62
- data/features/kitchen_sink_command.feature +0 -30
- data/features/kitchen_test_command.feature +0 -88
- data/features/step_definitions/gem_steps.rb +0 -24
- data/features/step_definitions/git_steps.rb +0 -5
- data/features/step_definitions/output_steps.rb +0 -5
- data/features/support/env.rb +0 -74
- data/spec/kitchen/base64_stream_spec.rb +0 -74
- data/spec/kitchen/cli_spec.rb +0 -54
- data/spec/kitchen/collection_spec.rb +0 -76
- data/spec/kitchen/color_spec.rb +0 -51
- data/spec/kitchen/config_spec.rb +0 -434
- data/spec/kitchen/configurable_spec.rb +0 -1113
- data/spec/kitchen/data_munger_spec.rb +0 -2800
- data/spec/kitchen/diagnostic_spec.rb +0 -128
- data/spec/kitchen/driver/base_spec.rb +0 -132
- data/spec/kitchen/driver/dummy_spec.rb +0 -193
- data/spec/kitchen/driver/exec_spec.rb +0 -75
- data/spec/kitchen/driver/proxy_spec.rb +0 -127
- data/spec/kitchen/driver/ssh_base_spec.rb +0 -1136
- data/spec/kitchen/driver_spec.rb +0 -106
- data/spec/kitchen/errors_spec.rb +0 -317
- data/spec/kitchen/instance_spec.rb +0 -1372
- data/spec/kitchen/lazy_hash_spec.rb +0 -113
- data/spec/kitchen/lifecycle_hooks_spec.rb +0 -171
- data/spec/kitchen/loader/yaml_spec.rb +0 -787
- data/spec/kitchen/logger_spec.rb +0 -425
- data/spec/kitchen/logging_spec.rb +0 -56
- data/spec/kitchen/login_command_spec.rb +0 -67
- data/spec/kitchen/metadata_chopper_spec.rb +0 -79
- data/spec/kitchen/platform_spec.rb +0 -88
- data/spec/kitchen/provisioner/base_spec.rb +0 -393
- data/spec/kitchen/provisioner/chef/policyfile_spec.rb +0 -140
- data/spec/kitchen/provisioner/chef_apply_spec.rb +0 -131
- data/spec/kitchen/provisioner/chef_base_spec.rb +0 -1565
- data/spec/kitchen/provisioner/chef_solo_spec.rb +0 -602
- data/spec/kitchen/provisioner/chef_zero_spec.rb +0 -1013
- data/spec/kitchen/provisioner/dummy_spec.rb +0 -96
- data/spec/kitchen/provisioner/shell_spec.rb +0 -623
- data/spec/kitchen/provisioner_spec.rb +0 -101
- data/spec/kitchen/shell_out_spec.rb +0 -146
- data/spec/kitchen/ssh_spec.rb +0 -584
- data/spec/kitchen/state_file_spec.rb +0 -122
- data/spec/kitchen/suite_spec.rb +0 -61
- data/spec/kitchen/transport/base_spec.rb +0 -140
- data/spec/kitchen/transport/exec_spec.rb +0 -79
- data/spec/kitchen/transport/ssh_spec.rb +0 -1317
- data/spec/kitchen/transport/winrm_spec.rb +0 -1320
- data/spec/kitchen/transport_spec.rb +0 -106
- data/spec/kitchen/util_spec.rb +0 -250
- data/spec/kitchen/verifier/base_spec.rb +0 -346
- data/spec/kitchen/verifier/busser_spec.rb +0 -580
- data/spec/kitchen/verifier/dummy_spec.rb +0 -96
- data/spec/kitchen/verifier/shell_spec.rb +0 -157
- data/spec/kitchen/verifier_spec.rb +0 -114
- data/spec/kitchen_spec.rb +0 -112
- data/spec/spec_helper.rb +0 -110
- data/spec/support/powershell_max_size_spec.rb +0 -39
- data/test-kitchen.gemspec +0 -49
- data/test/cookbooks/test_cookbook/metadata.rb +0 -6
- data/test/cookbooks/test_cookbook/recipes/default.rb +0 -1
- data/test/integration/default/default_spec.rb +0 -3
- data/testing_windows.md +0 -38
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2013, Fletcher Nichol
|
|
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_relative "../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen/errors"
|
|
22
|
-
require "kitchen/state_file"
|
|
23
|
-
require "kitchen/util"
|
|
24
|
-
|
|
25
|
-
class YamledState
|
|
26
|
-
attr_accessor :yoinks
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe Kitchen::StateFile do
|
|
30
|
-
let(:state_file) { Kitchen::StateFile.new("/tmp", "oftheunion") }
|
|
31
|
-
let(:file_name) { "/tmp/.kitchen/oftheunion.yml" }
|
|
32
|
-
|
|
33
|
-
before do
|
|
34
|
-
FakeFS.activate!
|
|
35
|
-
FileUtils.mkdir_p("/tmp")
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
after do
|
|
39
|
-
FakeFS.deactivate!
|
|
40
|
-
FakeFS::FileSystem.clear
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
describe "#read" do
|
|
44
|
-
it "returns an empty hash if the file does not exist" do
|
|
45
|
-
state_file.read.must_equal({})
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "returns and empty hash if the file is zero length" do
|
|
49
|
-
stub_state_file!("")
|
|
50
|
-
|
|
51
|
-
state_file.read.must_equal({})
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "returns a Hash with symbolized keys from the state file" do
|
|
55
|
-
stub_state_file!
|
|
56
|
-
|
|
57
|
-
state_file.read.must_equal(
|
|
58
|
-
cloud_id: 42,
|
|
59
|
-
flavor: "extra_crispy"
|
|
60
|
-
)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it "arbitrary objects aren't deserialized from state file" do
|
|
64
|
-
stub_state_file! <<-'YAML'.gsub(/^ {8}/, "")
|
|
65
|
-
--- !ruby/object:YamledState
|
|
66
|
-
yoinks: zoinks
|
|
67
|
-
YAML
|
|
68
|
-
|
|
69
|
-
proc { state_file.read }.must_raise Kitchen::StateFileLoadError
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
it "raises a StateFileLoadError if the state file cannot be parsed" do
|
|
73
|
-
stub_state_file!("&*%^*")
|
|
74
|
-
|
|
75
|
-
proc { state_file.read }.must_raise Kitchen::StateFileLoadError
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
describe "#write" do
|
|
80
|
-
it "creates the directory path to the state file" do
|
|
81
|
-
File.directory?("/tmp/.kitchen").must_equal false
|
|
82
|
-
state_file.write({})
|
|
83
|
-
File.directory?("/tmp/.kitchen").must_equal true
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "writes a state file with stringified keys" do
|
|
87
|
-
state_file.write(thekey: "thyself")
|
|
88
|
-
|
|
89
|
-
IO.read(file_name).split("\n").must_include "thekey: thyself"
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
describe "#destroy" do
|
|
94
|
-
it "executes if no file exists" do
|
|
95
|
-
File.exist?(file_name).must_equal false
|
|
96
|
-
state_file.destroy
|
|
97
|
-
File.exist?(file_name).must_equal false
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it "deletes the state file" do
|
|
101
|
-
stub_state_file!
|
|
102
|
-
state_file.destroy
|
|
103
|
-
|
|
104
|
-
File.exist?(file_name).must_equal false
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
private
|
|
109
|
-
|
|
110
|
-
def stub_state_file!(yaml_string = nil)
|
|
111
|
-
if yaml_string.nil?
|
|
112
|
-
yaml_string = <<-'YAML'.gsub(/^ {8}/, "")
|
|
113
|
-
---
|
|
114
|
-
cloud_id: 42
|
|
115
|
-
flavor: extra_crispy
|
|
116
|
-
YAML
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
FileUtils.mkdir_p(File.dirname(file_name))
|
|
120
|
-
File.open(file_name, "wb") { |f| f.write(yaml_string) }
|
|
121
|
-
end
|
|
122
|
-
end
|
data/spec/kitchen/suite_spec.rb
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2012, Fletcher Nichol
|
|
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_relative "../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen/errors"
|
|
22
|
-
require "kitchen/suite"
|
|
23
|
-
|
|
24
|
-
describe Kitchen::Suite do
|
|
25
|
-
let(:opts) do
|
|
26
|
-
{
|
|
27
|
-
name: "suitezy",
|
|
28
|
-
includes: %w{testbuntu testcent},
|
|
29
|
-
excludes: %w{prodbuntu},
|
|
30
|
-
}
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
let(:suite) { Kitchen::Suite.new(opts) }
|
|
34
|
-
|
|
35
|
-
it "returns the name" do
|
|
36
|
-
suite.name.must_equal "suitezy"
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "raises an ArgumentError if name is missing" do
|
|
40
|
-
opts.delete(:name)
|
|
41
|
-
proc { Kitchen::Suite.new(opts) }.must_raise Kitchen::ClientError
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it "returns the includes" do
|
|
45
|
-
suite.includes.must_equal %w{testbuntu testcent}
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "returns an empty Array when includes not given" do
|
|
49
|
-
opts.delete(:includes)
|
|
50
|
-
suite.includes.must_equal []
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it "returns the excludes" do
|
|
54
|
-
suite.excludes.must_equal %w{prodbuntu}
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
it "returns an empty Array when excludes not given" do
|
|
58
|
-
opts.delete(:excludes)
|
|
59
|
-
suite.excludes.must_equal []
|
|
60
|
-
end
|
|
61
|
-
end
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2015, Fletcher Nichol
|
|
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_relative "../../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen"
|
|
22
|
-
|
|
23
|
-
describe Kitchen::Transport::Base do
|
|
24
|
-
let(:logged_output) { StringIO.new }
|
|
25
|
-
let(:logger) { Logger.new(logged_output) }
|
|
26
|
-
let(:config) { Hash.new }
|
|
27
|
-
|
|
28
|
-
let(:instance) do
|
|
29
|
-
stub(name: "coolbeans", logger: logger)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
let(:transport) do
|
|
33
|
-
Kitchen::Transport::Base.new(config).finalize_config!(instance)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it "has an #connection method which raises a ClientError" do
|
|
37
|
-
proc { transport.connection({}) }.must_raise Kitchen::ClientError
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
describe "#logger" do
|
|
41
|
-
before { @klog = Kitchen.logger }
|
|
42
|
-
after { Kitchen.logger = @klog }
|
|
43
|
-
|
|
44
|
-
it "returns the instance's logger" do
|
|
45
|
-
transport.send(:logger).must_equal logger
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "returns the default logger if instance's logger is not set" do
|
|
49
|
-
transport = Kitchen::Transport::Base.new(config)
|
|
50
|
-
Kitchen.logger = "yep"
|
|
51
|
-
|
|
52
|
-
transport.send(:logger).must_equal Kitchen.logger
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
describe Kitchen::Transport::TransportFailed do
|
|
57
|
-
let(:failure_with_no_exit_code) { Kitchen::Transport::TransportFailed.new("Boom") }
|
|
58
|
-
let(:failure_with_exit_code) { Kitchen::Transport::TransportFailed.new("Boom", 123) }
|
|
59
|
-
|
|
60
|
-
describe "when no exit code is provided" do
|
|
61
|
-
it "#exit_code is nil" do
|
|
62
|
-
failure_with_no_exit_code.exit_code.must_be_nil
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
describe "when an exit code is provided" do
|
|
67
|
-
it "#exit_code returns the supplied exit code" do
|
|
68
|
-
failure_with_exit_code.exit_code.must_equal 123
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
describe Kitchen::Transport::Base::Connection do
|
|
75
|
-
let(:logged_output) { StringIO.new }
|
|
76
|
-
let(:logger) { Logger.new(logged_output) }
|
|
77
|
-
let(:options) { { logger: logger } }
|
|
78
|
-
|
|
79
|
-
let(:connection) do
|
|
80
|
-
Kitchen::Transport::Base::Connection.new(options)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "has a #close method that does nothing" do
|
|
84
|
-
connection.close.must_be_nil
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "has an #execute method which raises a ClientError" do
|
|
88
|
-
proc { connection.execute("boo") }.must_raise Kitchen::ClientError
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
it "has a #login_command method which raises an ActionFailed" do
|
|
92
|
-
proc { connection.login_command }.must_raise Kitchen::ActionFailed
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
it "has an #upload method which raises a ClientError" do
|
|
96
|
-
proc { connection.upload(["file"], "/path/to") }
|
|
97
|
-
.must_raise Kitchen::ClientError
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
it "has an #download method which raises a ClientError" do
|
|
101
|
-
proc { connection.download(["remote"], "local") }
|
|
102
|
-
.must_raise Kitchen::ClientError
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it "has a #wait_until_ready method that does nothing" do
|
|
106
|
-
connection.wait_until_ready.must_be_nil
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
describe "#execute_with_retry" do
|
|
110
|
-
let(:failure_with_exit_code) { Kitchen::Transport::TransportFailed.new("Boom", 123) }
|
|
111
|
-
|
|
112
|
-
it "raises ClientError with no retries" do
|
|
113
|
-
proc { connection.execute_with_retry("hi", [], nil, nil) }
|
|
114
|
-
.must_raise Kitchen::ClientError
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "retries three times" do
|
|
118
|
-
connection.expects(:execute).with("Hi").returns("Hello")
|
|
119
|
-
connection.expects(:debug).with("Attempting to execute command - try 3 of 3.")
|
|
120
|
-
connection.expects(:execute).with("Hi").raises(failure_with_exit_code)
|
|
121
|
-
connection.expects(:debug).with("Attempting to execute command - try 2 of 3.")
|
|
122
|
-
connection.expects(:execute).with("Hi").raises(failure_with_exit_code)
|
|
123
|
-
connection.expects(:debug).with("Attempting to execute command - try 1 of 3.")
|
|
124
|
-
|
|
125
|
-
connection.execute_with_retry("Hi", [123], 3, 1).must_equal "Hello"
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
describe "#retry?" do
|
|
130
|
-
it "raises an exception when multiple retryable exit codes are passed as a String" do
|
|
131
|
-
proc { connection.retry?(2, 2, "35 1", 35) }
|
|
132
|
-
.must_raise("undefined method `flatten' for \"35 1\":String")
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
it "returns true when the retryable exit codes are formatted in a nested array" do
|
|
136
|
-
connection.retry?(1, 2, [[35, 1]], 35).must_equal true
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
end
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
#
|
|
6
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
-
#
|
|
8
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
-
# See the License for the specific language governing permissions and
|
|
12
|
-
# limitations under the License.
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
require_relative "../../spec_helper"
|
|
16
|
-
|
|
17
|
-
require "kitchen/transport/exec"
|
|
18
|
-
|
|
19
|
-
describe Kitchen::Transport::Ssh do
|
|
20
|
-
let(:logged_output) { StringIO.new }
|
|
21
|
-
let(:logger) { Logger.new(logged_output) }
|
|
22
|
-
let(:config) { Hash.new }
|
|
23
|
-
let(:state) { Hash.new }
|
|
24
|
-
|
|
25
|
-
let(:instance) do
|
|
26
|
-
stub(name: "coolbeans", logger: logger, to_str: "instance")
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
let(:transport) do
|
|
30
|
-
Kitchen::Transport::Exec.new(config).finalize_config!(instance)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "provisioner api_version is 1" do
|
|
34
|
-
transport.diagnose_plugin[:api_version].must_equal 1
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "plugin_version is set to Kitchen::VERSION" do
|
|
38
|
-
transport.diagnose_plugin[:version].must_equal Kitchen::VERSION
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe "#connection" do
|
|
42
|
-
it "returns a Kitchen::Transport::Exec::Connection object" do
|
|
43
|
-
transport.connection(state).must_be_kind_of Kitchen::Transport::Exec::Connection
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
describe Kitchen::Transport::Exec::Connection do
|
|
49
|
-
let(:logged_output) { StringIO.new }
|
|
50
|
-
let(:logger) { Logger.new(logged_output) }
|
|
51
|
-
|
|
52
|
-
let(:options) do
|
|
53
|
-
{ logger: logger }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
let(:connection) do
|
|
57
|
-
Kitchen::Transport::Exec::Connection.new(options)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
describe "#execute" do
|
|
61
|
-
it "runs the command" do
|
|
62
|
-
connection.expects(:run_command).with("do the thing")
|
|
63
|
-
connection.execute("do the thing")
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "ignores nil" do
|
|
67
|
-
connection.expects(:run_command).never
|
|
68
|
-
connection.execute(nil)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
describe "#upload" do
|
|
73
|
-
it "copies files" do
|
|
74
|
-
FileUtils.expects(:mkdir_p).with("/tmp/kitchen")
|
|
75
|
-
FileUtils.expects(:cp_r).with("/tmp/sandbox/cookbooks", "/tmp/kitchen")
|
|
76
|
-
connection.upload(%w{/tmp/sandbox/cookbooks}, "/tmp/kitchen")
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
@@ -1,1317 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
|
4
|
-
#
|
|
5
|
-
# Copyright (C) 2015, Fletcher Nichol
|
|
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_relative "../../spec_helper"
|
|
20
|
-
|
|
21
|
-
require "kitchen/transport/ssh"
|
|
22
|
-
require "net/ssh/test"
|
|
23
|
-
|
|
24
|
-
describe Kitchen::Transport::Ssh do
|
|
25
|
-
let(:logged_output) { StringIO.new }
|
|
26
|
-
let(:logger) { Logger.new(logged_output) }
|
|
27
|
-
let(:config) { Hash.new }
|
|
28
|
-
let(:state) { Hash.new }
|
|
29
|
-
|
|
30
|
-
let(:instance) do
|
|
31
|
-
stub(name: "coolbeans", logger: logger, to_str: "instance")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
let(:transport) do
|
|
35
|
-
Net::SSH::Test::Extensions::IO.with_test_extension { Kitchen::Transport::Ssh.new(config).finalize_config!(instance) }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "provisioner api_version is 1" do
|
|
39
|
-
transport.diagnose_plugin[:api_version].must_equal 1
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "plugin_version is set to Kitchen::VERSION" do
|
|
43
|
-
transport.diagnose_plugin[:version].must_equal Kitchen::VERSION
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
describe "default_config" do
|
|
47
|
-
it "sets :port to 22 by default" do
|
|
48
|
-
transport[:port].must_equal 22
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
it "sets :username to root by default" do
|
|
52
|
-
transport[:username].must_equal "root"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "sets :compression to true by default" do
|
|
56
|
-
transport[:compression].must_equal false
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "sets :compression to false if set to none" do
|
|
60
|
-
config[:compression] = "none"
|
|
61
|
-
|
|
62
|
-
transport[:compression].must_equal false
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "sets :compression to zlib@openssh.com if set to zlib" do
|
|
66
|
-
config[:compression] = "zlib"
|
|
67
|
-
|
|
68
|
-
transport[:compression].must_equal "zlib@openssh.com"
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "sets :compression_level to 6 by default" do
|
|
72
|
-
transport[:compression_level].must_equal 0
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "sets :compression_level to 6 if :compression is set to true" do
|
|
76
|
-
config[:compression] = true
|
|
77
|
-
|
|
78
|
-
transport[:compression_level].must_equal 6
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "sets :keepalive to true by default" do
|
|
82
|
-
transport[:keepalive].must_equal true
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it "sets :keepalive_interval to 60 by default" do
|
|
86
|
-
transport[:keepalive_interval].must_equal 60
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "sets :connection_timeout to 15 by default" do
|
|
90
|
-
transport[:connection_timeout].must_equal 15
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it "sets :connection_retries to 5 by default" do
|
|
94
|
-
transport[:connection_retries].must_equal 5
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it "sets :connection_retry_sleep to 1 by default" do
|
|
98
|
-
transport[:connection_retry_sleep].must_equal 1
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it "sets :max_wait_until_ready to 600 by default" do
|
|
102
|
-
transport[:max_wait_until_ready].must_equal 600
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it "sets :ssh_key to nil by default" do
|
|
106
|
-
transport[:ssh_key].must_be_nil
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "sets :ssh_key_only to nil by default" do
|
|
110
|
-
transport[:ssh_key_only].must_be_nil
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "expands :ssh_path path if set" do
|
|
114
|
-
config[:kitchen_root] = "/rooty"
|
|
115
|
-
config[:ssh_key] = "my_key"
|
|
116
|
-
|
|
117
|
-
transport[:ssh_key].must_equal os_safe_root_path("/rooty/my_key")
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
it "sets :max_ssh_sessions to 9 by default" do
|
|
121
|
-
transport[:max_ssh_sessions].must_equal 9
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it "sets :ssh_http_proxy to nil by default" do
|
|
125
|
-
transport[:ssh_http_proxy].must_be_nil
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
it "sets :ssh_http_proxy_port to nil by default" do
|
|
129
|
-
transport[:ssh_http_proxy_port].must_be_nil
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
it "sets :ssh_http_proxy_user to nil by default" do
|
|
133
|
-
transport[:ssh_http_proxy_user].must_be_nil
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
it "sets :ssh_http_proxy_password to nil by default" do
|
|
137
|
-
transport[:ssh_http_proxy_password].must_be_nil
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
it "sets :ssh_gateway to nil by default" do
|
|
141
|
-
transport[:ssh_gateway].must_be_nil
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
it "sets :ssh_gateway_username to nil by default" do
|
|
145
|
-
transport[:ssh_gateway_username].must_be_nil
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
it "sets :ssh_gateway_port to 22 by default" do
|
|
149
|
-
transport[:ssh_gateway_port].must_equal 22
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
describe "#connection" do
|
|
154
|
-
let(:klass) { Kitchen::Transport::Ssh::Connection }
|
|
155
|
-
let(:options_http_proxy) { Hash.new }
|
|
156
|
-
let(:proxy_conn) do
|
|
157
|
-
state[:ssh_http_proxy] = "ssh_http_proxy_from_state"
|
|
158
|
-
state[:ssh_http_proxy_port] = "ssh_http_proxy_port_from_state"
|
|
159
|
-
options_http_proxy[:user] = state[:ssh_http_proxy_user]
|
|
160
|
-
options_http_proxy[:password] = state[:ssh_http_proxy_password]
|
|
161
|
-
Net::SSH::Proxy::HTTP.new(state[:ssh_http_proxy], state[:ssh_http_proxy_port], options_http_proxy)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
165
|
-
def self.common_connection_specs
|
|
166
|
-
before do
|
|
167
|
-
Net::SSH::Proxy::HTTP.stubs(:new).returns(proxy_conn)
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
it "returns a Kitchen::Transport::Ssh::Connection object" do
|
|
171
|
-
transport.connection(state).must_be_kind_of klass
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
it "sets the :logger to the transport's logger" do
|
|
175
|
-
klass.expects(:new).with do |hash|
|
|
176
|
-
hash[:logger] == logger
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
make_connection
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
it "sets the :user_known_hosts_file to /dev/null" do
|
|
183
|
-
klass.expects(:new).with do |hash|
|
|
184
|
-
hash[:user_known_hosts_file] == "/dev/null"
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
make_connection
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
it "sets the :verify_host_key flag to false" do
|
|
191
|
-
klass.expects(:new).with do |hash|
|
|
192
|
-
hash[:verify_host_key] == false
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
make_connection
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
it "sets :hostname from config" do
|
|
199
|
-
config[:hostname] = "host_from_config"
|
|
200
|
-
|
|
201
|
-
klass.expects(:new).with do |hash|
|
|
202
|
-
hash[:hostname] == "host_from_config"
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
make_connection
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
it "sets :hostname from state over config data" do
|
|
209
|
-
state[:hostname] = "host_from_state"
|
|
210
|
-
config[:hostname] = "host_from_config"
|
|
211
|
-
|
|
212
|
-
klass.expects(:new).with do |hash|
|
|
213
|
-
hash[:hostname] == "host_from_state"
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
make_connection
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it "sets :port from config" do
|
|
220
|
-
config[:port] = "port_from_config"
|
|
221
|
-
|
|
222
|
-
klass.expects(:new).with do |hash|
|
|
223
|
-
hash[:port] == "port_from_config"
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
make_connection
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
it "sets :port from state over config data" do
|
|
230
|
-
state[:port] = "port_from_state"
|
|
231
|
-
config[:port] = "port_from_config"
|
|
232
|
-
|
|
233
|
-
klass.expects(:new).with do |hash|
|
|
234
|
-
hash[:port] == "port_from_state"
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
make_connection
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it "sets :username from config" do
|
|
241
|
-
config[:username] = "user_from_config"
|
|
242
|
-
|
|
243
|
-
klass.expects(:new).with do |hash|
|
|
244
|
-
hash[:username] == "user_from_config"
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
make_connection
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
it "sets :username from state over config data" do
|
|
251
|
-
state[:username] = "user_from_state"
|
|
252
|
-
config[:username] = "user_from_config"
|
|
253
|
-
|
|
254
|
-
klass.expects(:new).with do |hash|
|
|
255
|
-
hash[:username] == "user_from_state"
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
make_connection
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
it "sets :compression from config" do
|
|
262
|
-
config[:compression] = "none"
|
|
263
|
-
|
|
264
|
-
klass.expects(:new).with do |hash|
|
|
265
|
-
hash[:compression] == false
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
make_connection
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
it "sets :compression from state over config data" do
|
|
272
|
-
state[:compression] = "none"
|
|
273
|
-
config[:compression] = "zlib"
|
|
274
|
-
|
|
275
|
-
klass.expects(:new).with do |hash|
|
|
276
|
-
hash[:compression] == "none"
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
make_connection
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
it "sets :compression_level from config" do
|
|
283
|
-
config[:compression_level] = 9999
|
|
284
|
-
|
|
285
|
-
klass.expects(:new).with do |hash|
|
|
286
|
-
hash[:compression_level] == 9999
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
make_connection
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
it "sets :compression_level from state over config data" do
|
|
293
|
-
state[:compression_level] = 9999
|
|
294
|
-
config[:compression_level] = 1111
|
|
295
|
-
|
|
296
|
-
klass.expects(:new).with do |hash|
|
|
297
|
-
hash[:compression_level] == 9999
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
make_connection
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
it "sets :timeout from :connection_timeout in config" do
|
|
304
|
-
config[:connection_timeout] = "timeout_from_config"
|
|
305
|
-
|
|
306
|
-
klass.expects(:new).with do |hash|
|
|
307
|
-
hash[:timeout] == "timeout_from_config"
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
make_connection
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
it "sets :timeout from :connection_timeout in state over config data" do
|
|
314
|
-
state[:connection_timeout] = "timeout_from_state"
|
|
315
|
-
config[:connection_timeout] = "timeout_from_config"
|
|
316
|
-
|
|
317
|
-
klass.expects(:new).with do |hash|
|
|
318
|
-
hash[:timeout] == "timeout_from_state"
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
make_connection
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
it "sets :keepalive from config" do
|
|
325
|
-
config[:keepalive] = "keepalive_from_config"
|
|
326
|
-
|
|
327
|
-
klass.expects(:new).with do |hash|
|
|
328
|
-
hash[:keepalive] == "keepalive_from_config"
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
make_connection
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
it "sets :keepalive from state over config data" do
|
|
335
|
-
state[:keepalive] = "keepalive_from_state"
|
|
336
|
-
config[:keepalive] = "keepalive_from_config"
|
|
337
|
-
|
|
338
|
-
klass.expects(:new).with do |hash|
|
|
339
|
-
hash[:keepalive] == "keepalive_from_state"
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
make_connection
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
it "sets :keepalive_interval from config" do
|
|
346
|
-
config[:keepalive_interval] = "interval_from_config"
|
|
347
|
-
|
|
348
|
-
klass.expects(:new).with do |hash|
|
|
349
|
-
hash[:keepalive_interval] == "interval_from_config"
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
make_connection
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
it "sets :keepalive_interval from state over config data" do
|
|
356
|
-
state[:keepalive_interval] = "interval_from_state"
|
|
357
|
-
config[:keepalive_interval] = "interval_from_config"
|
|
358
|
-
|
|
359
|
-
klass.expects(:new).with do |hash|
|
|
360
|
-
hash[:keepalive_interval] == "interval_from_state"
|
|
361
|
-
end
|
|
362
|
-
|
|
363
|
-
make_connection
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
it "sets :connection_retries from config" do
|
|
367
|
-
config[:connection_retries] = "retries_from_config"
|
|
368
|
-
|
|
369
|
-
klass.expects(:new).with do |hash|
|
|
370
|
-
hash[:connection_retries] == "retries_from_config"
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
make_connection
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
it "sets :connection_retries from state over config data" do
|
|
377
|
-
state[:connection_retries] = "retries_from_state"
|
|
378
|
-
config[:connection_retries] = "retries_from_config"
|
|
379
|
-
|
|
380
|
-
klass.expects(:new).with do |hash|
|
|
381
|
-
hash[:connection_retries] == "retries_from_state"
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
make_connection
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
it "sets :connection_retry_sleep from config" do
|
|
388
|
-
config[:connection_retry_sleep] = "sleep_from_config"
|
|
389
|
-
|
|
390
|
-
klass.expects(:new).with do |hash|
|
|
391
|
-
hash[:connection_retry_sleep] == "sleep_from_config"
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
make_connection
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
it "sets :connection_retry_sleep from state over config data" do
|
|
398
|
-
state[:connection_retry_sleep] = "sleep_from_state"
|
|
399
|
-
config[:connection_retry_sleep] = "sleep_from_config"
|
|
400
|
-
|
|
401
|
-
klass.expects(:new).with do |hash|
|
|
402
|
-
hash[:connection_retry_sleep] == "sleep_from_state"
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
make_connection
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
it "sets :max_wait_until_ready from config" do
|
|
409
|
-
config[:max_wait_until_ready] = "max_from_config"
|
|
410
|
-
|
|
411
|
-
klass.expects(:new).with do |hash|
|
|
412
|
-
hash[:max_wait_until_ready] == "max_from_config"
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
make_connection
|
|
416
|
-
end
|
|
417
|
-
|
|
418
|
-
it "sets :max_wait_until_ready from state over config data" do
|
|
419
|
-
state[:max_wait_until_ready] = "max_from_state"
|
|
420
|
-
config[:max_wait_until_ready] = "max_from_config"
|
|
421
|
-
|
|
422
|
-
klass.expects(:new).with do |hash|
|
|
423
|
-
hash[:max_wait_until_ready] == "max_from_state"
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
make_connection
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
it "sets :keys_only to true if :ssh_key is set in config" do
|
|
430
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
431
|
-
|
|
432
|
-
klass.expects(:new).with do |hash|
|
|
433
|
-
hash[:keys_only] == true
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
make_connection
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
it "sets :auth_methods to only publickey if :ssh_key is set in config" do
|
|
440
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
441
|
-
|
|
442
|
-
klass.expects(:new).with do |hash|
|
|
443
|
-
hash[:auth_methods] == ["publickey"]
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
make_connection
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
it "sets :keys_only to true if :ssh_key is set in state" do
|
|
450
|
-
state[:ssh_key] = "ssh_key_from_config"
|
|
451
|
-
config[:ssh_key] = false
|
|
452
|
-
|
|
453
|
-
klass.expects(:new).with do |hash|
|
|
454
|
-
hash[:keys_only] == true
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
make_connection
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
it "sets :proxy to proxy if :ssh_http_proxy is set in state" do
|
|
461
|
-
config[:ssh_http_proxy] = true
|
|
462
|
-
|
|
463
|
-
klass.expects(:new).with do |hash|
|
|
464
|
-
hash[:proxy] == proxy_conn
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
make_connection
|
|
468
|
-
end
|
|
469
|
-
|
|
470
|
-
it "sets :keys to an array if :ssh_key is set in config" do
|
|
471
|
-
config[:kitchen_root] = "/r"
|
|
472
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
473
|
-
|
|
474
|
-
klass.expects(:new).with do |hash|
|
|
475
|
-
hash[:keys] == [os_safe_root_path("/r/ssh_key_from_config")]
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
make_connection
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
it "sets :keys to an array if :ssh_key is set in state" do
|
|
482
|
-
state[:ssh_key] = "ssh_key_from_state"
|
|
483
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
484
|
-
|
|
485
|
-
klass.expects(:new).with do |hash|
|
|
486
|
-
hash[:keys] == ["ssh_key_from_state"]
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
make_connection
|
|
490
|
-
end
|
|
491
|
-
|
|
492
|
-
it "does not set :keys_only if :ssh_key is set in config but password is set" do
|
|
493
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
494
|
-
config[:password] = "password"
|
|
495
|
-
|
|
496
|
-
klass.expects(:new).with do |hash|
|
|
497
|
-
hash[:keys_only].nil?
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
make_connection
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
it "does not set :auth_methods if :ssh_key is set in config but password is set" do
|
|
504
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
505
|
-
config[:password] = "password"
|
|
506
|
-
|
|
507
|
-
klass.expects(:new).with do |hash|
|
|
508
|
-
hash[:auth_methods].nil?
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
make_connection
|
|
512
|
-
end
|
|
513
|
-
|
|
514
|
-
it "does not set :keys_only if :ssh_key is set in state but password is set" do
|
|
515
|
-
state[:ssh_key] = "ssh_key_from_config"
|
|
516
|
-
config[:ssh_key] = false
|
|
517
|
-
config[:password] = "password"
|
|
518
|
-
|
|
519
|
-
klass.expects(:new).with do |hash|
|
|
520
|
-
hash[:keys_only].nil?
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
make_connection
|
|
524
|
-
end
|
|
525
|
-
|
|
526
|
-
it "does not set :keys to an array if :ssh_key is set in config but password is set" do
|
|
527
|
-
config[:kitchen_root] = "/r"
|
|
528
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
529
|
-
config[:password] = "password"
|
|
530
|
-
|
|
531
|
-
klass.expects(:new).with do |hash|
|
|
532
|
-
hash[:keys].nil?
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
make_connection
|
|
536
|
-
end
|
|
537
|
-
|
|
538
|
-
it "does not set :keys to an array if :ssh_key is set in state but password is set" do
|
|
539
|
-
state[:ssh_key] = "ssh_key_from_state"
|
|
540
|
-
config[:ssh_key] = "ssh_key_from_config"
|
|
541
|
-
config[:password] = "password"
|
|
542
|
-
|
|
543
|
-
klass.expects(:new).with do |hash|
|
|
544
|
-
hash[:keys].nil?
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
make_connection
|
|
548
|
-
end
|
|
549
|
-
|
|
550
|
-
it "sets :auth_methods to only publickey if :ssh_key_only is set in config" do
|
|
551
|
-
config[:ssh_key_only] = true
|
|
552
|
-
|
|
553
|
-
klass.expects(:new).with do |hash|
|
|
554
|
-
hash[:auth_methods] == ["publickey"]
|
|
555
|
-
end
|
|
556
|
-
|
|
557
|
-
make_connection
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
it "passes in :password if set in config" do
|
|
561
|
-
config[:password] = "password_from_config"
|
|
562
|
-
|
|
563
|
-
klass.expects(:new).with do |hash|
|
|
564
|
-
hash[:password] == "password_from_config"
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
make_connection
|
|
568
|
-
end
|
|
569
|
-
|
|
570
|
-
it "passes in :password from state over config data" do
|
|
571
|
-
state[:password] = "password_from_state"
|
|
572
|
-
config[:password] = "password_from_config"
|
|
573
|
-
|
|
574
|
-
klass.expects(:new).with do |hash|
|
|
575
|
-
hash[:password] == "password_from_state"
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
make_connection
|
|
579
|
-
end
|
|
580
|
-
|
|
581
|
-
it "passes in :forward_agent if set in config" do
|
|
582
|
-
config[:forward_agent] = "forward_agent_from_config"
|
|
583
|
-
|
|
584
|
-
klass.expects(:new).with do |hash|
|
|
585
|
-
hash[:forward_agent] == "forward_agent_from_config"
|
|
586
|
-
end
|
|
587
|
-
|
|
588
|
-
make_connection
|
|
589
|
-
end
|
|
590
|
-
|
|
591
|
-
it "passes in :forward_agent from state over config data" do
|
|
592
|
-
state[:forward_agent] = "forward_agent_from_state"
|
|
593
|
-
config[:forward_agent] = "forward_agent_from_config"
|
|
594
|
-
|
|
595
|
-
klass.expects(:new).with do |hash|
|
|
596
|
-
hash[:forward_agent] == "forward_agent_from_state"
|
|
597
|
-
end
|
|
598
|
-
|
|
599
|
-
make_connection
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
it "returns the same connection when called again with same state" do
|
|
603
|
-
first_connection = make_connection(state)
|
|
604
|
-
second_connection = make_connection(state)
|
|
605
|
-
|
|
606
|
-
first_connection.object_id.must_equal second_connection.object_id
|
|
607
|
-
end
|
|
608
|
-
|
|
609
|
-
it "logs a debug message when the connection is reused" do
|
|
610
|
-
make_connection(state)
|
|
611
|
-
make_connection(state)
|
|
612
|
-
|
|
613
|
-
logged_output.string.lines.count do |l|
|
|
614
|
-
l =~ debug_line_with("[SSH] reusing existing connection ")
|
|
615
|
-
end.must_equal 1
|
|
616
|
-
end
|
|
617
|
-
|
|
618
|
-
it "returns a new connection when called again if state differs" do
|
|
619
|
-
first_connection = make_connection(state)
|
|
620
|
-
second_connection = make_connection(state.merge(port: 9000))
|
|
621
|
-
|
|
622
|
-
first_connection.object_id.wont_equal second_connection.object_id
|
|
623
|
-
end
|
|
624
|
-
|
|
625
|
-
it "closes first connection when a second is created" do
|
|
626
|
-
first_connection = make_connection(state)
|
|
627
|
-
first_connection.expects(:close)
|
|
628
|
-
|
|
629
|
-
make_connection(state.merge(port: 9000))
|
|
630
|
-
end
|
|
631
|
-
|
|
632
|
-
it "logs a debug message a second connection is created" do
|
|
633
|
-
make_connection(state)
|
|
634
|
-
make_connection(state.merge(port: 9000))
|
|
635
|
-
|
|
636
|
-
logged_output.string.lines.count do |l|
|
|
637
|
-
l =~ debug_line_with("[SSH] shutting previous connection ")
|
|
638
|
-
end.must_equal 1
|
|
639
|
-
end
|
|
640
|
-
end
|
|
641
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
642
|
-
|
|
643
|
-
describe "called without a block" do
|
|
644
|
-
def make_connection(s = state)
|
|
645
|
-
transport.connection(s)
|
|
646
|
-
end
|
|
647
|
-
|
|
648
|
-
common_connection_specs
|
|
649
|
-
end
|
|
650
|
-
|
|
651
|
-
describe "called with a block" do
|
|
652
|
-
def make_connection(s = state)
|
|
653
|
-
transport.connection(s) do |conn|
|
|
654
|
-
conn
|
|
655
|
-
end
|
|
656
|
-
end
|
|
657
|
-
|
|
658
|
-
common_connection_specs
|
|
659
|
-
end
|
|
660
|
-
end
|
|
661
|
-
|
|
662
|
-
def debug_line_with(msg)
|
|
663
|
-
/^D, .* : #{Regexp.escape(msg)}/
|
|
664
|
-
end
|
|
665
|
-
end
|
|
666
|
-
|
|
667
|
-
describe Kitchen::Transport::Ssh::Connection do
|
|
668
|
-
include Net::SSH::Test
|
|
669
|
-
# sadly, Net:SSH::Test includes a #connection method so we'll alias this one
|
|
670
|
-
# before redefining it
|
|
671
|
-
alias_method :net_ssh_connection, :connection
|
|
672
|
-
|
|
673
|
-
let(:logged_output) { StringIO.new }
|
|
674
|
-
let(:logger) { Logger.new(logged_output) }
|
|
675
|
-
let(:conn) { Net::SSH::Test::Extensions::IO.with_test_extension { net_ssh_connection } }
|
|
676
|
-
|
|
677
|
-
let(:options) do
|
|
678
|
-
{
|
|
679
|
-
logger: logger,
|
|
680
|
-
username: "me",
|
|
681
|
-
hostname: "foo",
|
|
682
|
-
port: 22,
|
|
683
|
-
max_ssh_sessions: 9,
|
|
684
|
-
}
|
|
685
|
-
end
|
|
686
|
-
|
|
687
|
-
let(:connection) do
|
|
688
|
-
Kitchen::Transport::Ssh::Connection.new(options)
|
|
689
|
-
end
|
|
690
|
-
|
|
691
|
-
before do
|
|
692
|
-
logger.level = Logger::DEBUG
|
|
693
|
-
Net::SSH.stubs(:start).returns(conn)
|
|
694
|
-
end
|
|
695
|
-
|
|
696
|
-
describe "establishing a connection" do
|
|
697
|
-
[
|
|
698
|
-
Errno::EACCES, Errno::EALREADY, Errno::EADDRINUSE, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
|
|
699
|
-
Errno::ECONNRESET, Errno::ENETUNREACH, Errno::EHOSTUNREACH, Errno::EPIPE,
|
|
700
|
-
Net::SSH::Disconnect, Net::SSH::AuthenticationFailed, Net::SSH::ConnectionTimeout,
|
|
701
|
-
Timeout::Error
|
|
702
|
-
].each do |klass|
|
|
703
|
-
describe "raising #{klass}" do
|
|
704
|
-
before do
|
|
705
|
-
Net::SSH.stubs(:start).raises(klass)
|
|
706
|
-
options[:connection_retries] = 3
|
|
707
|
-
options[:connection_retry_sleep] = 7
|
|
708
|
-
connection.stubs(:sleep)
|
|
709
|
-
end
|
|
710
|
-
|
|
711
|
-
it "raises an SshFailed exception" do
|
|
712
|
-
e = proc do
|
|
713
|
-
connection.execute("nope")
|
|
714
|
-
end.must_raise Kitchen::Transport::SshFailed
|
|
715
|
-
e.message.must_match regexify("SSH session could not be established")
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
it "attempts to connect :connection_retries times" do
|
|
719
|
-
begin
|
|
720
|
-
connection.execute("nope")
|
|
721
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
722
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
723
|
-
end
|
|
724
|
-
|
|
725
|
-
logged_output.string.lines.count do |l|
|
|
726
|
-
l =~ debug_line("[SSH] opening connection to me@foo<{:port=>22}>")
|
|
727
|
-
end.must_equal 3
|
|
728
|
-
end
|
|
729
|
-
|
|
730
|
-
it "sleeps for :connection_retry_sleep seconds between retries" do
|
|
731
|
-
connection.unstub(:sleep)
|
|
732
|
-
connection.expects(:sleep).with(7).twice
|
|
733
|
-
|
|
734
|
-
begin
|
|
735
|
-
connection.execute("nope")
|
|
736
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
737
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
738
|
-
end
|
|
739
|
-
end
|
|
740
|
-
|
|
741
|
-
it "logs the first 2 retry failures on info" do
|
|
742
|
-
begin
|
|
743
|
-
connection.execute("nope")
|
|
744
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
745
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
746
|
-
end
|
|
747
|
-
|
|
748
|
-
logged_output.string.lines.count do |l|
|
|
749
|
-
l =~ info_line_with(
|
|
750
|
-
"[SSH] connection failed, retrying in 7 seconds")
|
|
751
|
-
end.must_equal 2
|
|
752
|
-
end
|
|
753
|
-
|
|
754
|
-
it "logs the last retry failures on warn" do
|
|
755
|
-
begin
|
|
756
|
-
connection.execute("nope")
|
|
757
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
758
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
759
|
-
end
|
|
760
|
-
|
|
761
|
-
logged_output.string.lines.count do |l|
|
|
762
|
-
l =~ warn_line_with("[SSH] connection failed, terminating ")
|
|
763
|
-
end.must_equal 1
|
|
764
|
-
end
|
|
765
|
-
end
|
|
766
|
-
end
|
|
767
|
-
end
|
|
768
|
-
|
|
769
|
-
describe "#close" do
|
|
770
|
-
before do
|
|
771
|
-
story do |script|
|
|
772
|
-
channel = script.opens_channel
|
|
773
|
-
channel.sends_request_pty
|
|
774
|
-
channel.sends_exec("doit")
|
|
775
|
-
channel.gets_data("ok\n")
|
|
776
|
-
channel.gets_exit_status(0)
|
|
777
|
-
channel.gets_close
|
|
778
|
-
channel.sends_close
|
|
779
|
-
end
|
|
780
|
-
end
|
|
781
|
-
|
|
782
|
-
it "logger displays closing connection on debug" do
|
|
783
|
-
conn.expects(:close)
|
|
784
|
-
|
|
785
|
-
assert_scripted do
|
|
786
|
-
connection.execute("doit")
|
|
787
|
-
connection.close
|
|
788
|
-
end
|
|
789
|
-
|
|
790
|
-
logged_output.string.must_match debug_line(
|
|
791
|
-
"[SSH] closing connection to me@foo<{:port=>22}>"
|
|
792
|
-
)
|
|
793
|
-
end
|
|
794
|
-
|
|
795
|
-
it "only closes the connection once for multiple calls" do
|
|
796
|
-
conn.expects(:close).once
|
|
797
|
-
|
|
798
|
-
assert_scripted do
|
|
799
|
-
connection.execute("doit")
|
|
800
|
-
connection.close
|
|
801
|
-
connection.close
|
|
802
|
-
connection.close
|
|
803
|
-
end
|
|
804
|
-
end
|
|
805
|
-
end
|
|
806
|
-
|
|
807
|
-
describe "#execute" do
|
|
808
|
-
describe "for a successful command" do
|
|
809
|
-
before do
|
|
810
|
-
story do |script|
|
|
811
|
-
channel = script.opens_channel
|
|
812
|
-
channel.sends_request_pty
|
|
813
|
-
channel.sends_exec("doit")
|
|
814
|
-
channel.gets_data("ok\n")
|
|
815
|
-
channel.gets_extended_data("some stderr stuffs\n")
|
|
816
|
-
channel.gets_exit_status(0)
|
|
817
|
-
channel.gets_close
|
|
818
|
-
channel.sends_close
|
|
819
|
-
end
|
|
820
|
-
end
|
|
821
|
-
|
|
822
|
-
it "logger displays command on debug" do
|
|
823
|
-
assert_scripted { connection.execute("doit") }
|
|
824
|
-
|
|
825
|
-
logged_output.string.must_match debug_line(
|
|
826
|
-
"[SSH] me@foo<{:port=>22}> (doit)"
|
|
827
|
-
)
|
|
828
|
-
end
|
|
829
|
-
|
|
830
|
-
it "logger displays establishing connection on debug" do
|
|
831
|
-
assert_scripted { connection.execute("doit") }
|
|
832
|
-
|
|
833
|
-
logged_output.string.must_match debug_line(
|
|
834
|
-
"[SSH] opening connection to me@foo<{:port=>22}>"
|
|
835
|
-
)
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
it "logger captures stdout" do
|
|
839
|
-
assert_scripted { connection.execute("doit") }
|
|
840
|
-
|
|
841
|
-
logged_output.string.must_match(/^ok$/)
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
it "logger captures stderr" do
|
|
845
|
-
assert_scripted { connection.execute("doit") }
|
|
846
|
-
|
|
847
|
-
logged_output.string.must_match(/^some stderr stuffs$/)
|
|
848
|
-
end
|
|
849
|
-
end
|
|
850
|
-
|
|
851
|
-
describe "for a failed command" do
|
|
852
|
-
before do
|
|
853
|
-
story do |script|
|
|
854
|
-
channel = script.opens_channel
|
|
855
|
-
channel.sends_request_pty
|
|
856
|
-
channel.sends_exec("doit")
|
|
857
|
-
channel.gets_data("nope\n")
|
|
858
|
-
channel.gets_extended_data("youdead\n")
|
|
859
|
-
channel.gets_exit_status(42)
|
|
860
|
-
channel.gets_close
|
|
861
|
-
channel.sends_close
|
|
862
|
-
end
|
|
863
|
-
end
|
|
864
|
-
|
|
865
|
-
it "logger displays command on debug" do
|
|
866
|
-
begin
|
|
867
|
-
assert_scripted { connection.execute("doit") }
|
|
868
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
869
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
870
|
-
end
|
|
871
|
-
|
|
872
|
-
logged_output.string.must_match debug_line(
|
|
873
|
-
"[SSH] me@foo<{:port=>22}> (doit)"
|
|
874
|
-
)
|
|
875
|
-
end
|
|
876
|
-
|
|
877
|
-
it "logger displays establishing connection on debug" do
|
|
878
|
-
begin
|
|
879
|
-
assert_scripted { connection.execute("doit") }
|
|
880
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
881
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
882
|
-
end
|
|
883
|
-
|
|
884
|
-
logged_output.string.must_match debug_line(
|
|
885
|
-
"[SSH] opening connection to me@foo<{:port=>22}>"
|
|
886
|
-
)
|
|
887
|
-
end
|
|
888
|
-
|
|
889
|
-
it "logger captures stdout" do
|
|
890
|
-
begin
|
|
891
|
-
assert_scripted { connection.execute("doit") }
|
|
892
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
893
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
894
|
-
end
|
|
895
|
-
|
|
896
|
-
logged_output.string.must_match(/^nope$/)
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
it "logger captures stderr" do
|
|
900
|
-
begin
|
|
901
|
-
assert_scripted { connection.execute("doit") }
|
|
902
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
903
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
904
|
-
end
|
|
905
|
-
|
|
906
|
-
logged_output.string.must_match(/^youdead$/)
|
|
907
|
-
end
|
|
908
|
-
|
|
909
|
-
it "raises an SshFailed exception" do
|
|
910
|
-
err = proc do
|
|
911
|
-
assert_scripted { connection.execute("doit") }
|
|
912
|
-
end.must_raise Kitchen::Transport::SshFailed
|
|
913
|
-
err.message.must_equal "SSH exited (42) for command: [doit]"
|
|
914
|
-
end
|
|
915
|
-
|
|
916
|
-
it "returns the exit code with an SshFailed exception" do
|
|
917
|
-
begin
|
|
918
|
-
assert_scripted { connection.execute("doit") }
|
|
919
|
-
rescue Kitchen::Transport::SshFailed => e
|
|
920
|
-
e.exit_code.must_equal 42
|
|
921
|
-
end
|
|
922
|
-
end
|
|
923
|
-
end
|
|
924
|
-
|
|
925
|
-
describe "for an interrupted command" do
|
|
926
|
-
let(:conn) { mock("session") }
|
|
927
|
-
|
|
928
|
-
before do
|
|
929
|
-
Net::SSH.stubs(:start).returns(conn)
|
|
930
|
-
end
|
|
931
|
-
|
|
932
|
-
it "raises SshFailed when an SSH exception is raised" do
|
|
933
|
-
conn.stubs(:open_channel).raises(Net::SSH::Exception)
|
|
934
|
-
|
|
935
|
-
e = proc do
|
|
936
|
-
connection.execute("nope")
|
|
937
|
-
end.must_raise Kitchen::Transport::SshFailed
|
|
938
|
-
e.message.must_match regexify("SSH command failed")
|
|
939
|
-
end
|
|
940
|
-
end
|
|
941
|
-
|
|
942
|
-
describe "for a nil command" do
|
|
943
|
-
it "does not log on debug" do
|
|
944
|
-
connection.execute(nil)
|
|
945
|
-
|
|
946
|
-
logged_output.string.must_equal ""
|
|
947
|
-
end
|
|
948
|
-
end
|
|
949
|
-
end
|
|
950
|
-
|
|
951
|
-
describe "#login_command" do
|
|
952
|
-
let(:login_command) { connection.login_command }
|
|
953
|
-
let(:args) { login_command.arguments.join(" ") }
|
|
954
|
-
|
|
955
|
-
it "returns a LoginCommand" do
|
|
956
|
-
login_command.must_be_instance_of Kitchen::LoginCommand
|
|
957
|
-
end
|
|
958
|
-
|
|
959
|
-
it "is an SSH command" do
|
|
960
|
-
login_command.command.must_equal "ssh"
|
|
961
|
-
args.must_match %r{ me@foo$}
|
|
962
|
-
end
|
|
963
|
-
|
|
964
|
-
it "sets the UserKnownHostsFile option" do
|
|
965
|
-
args.must_match regexify("-o UserKnownHostsFile=/dev/null ")
|
|
966
|
-
end
|
|
967
|
-
|
|
968
|
-
it "sets the StrictHostKeyChecking option" do
|
|
969
|
-
args.must_match regexify(" -o StrictHostKeyChecking=no ")
|
|
970
|
-
end
|
|
971
|
-
|
|
972
|
-
it "won't set IdentitiesOnly option by default" do
|
|
973
|
-
args.wont_match regexify(" -o IdentitiesOnly=")
|
|
974
|
-
end
|
|
975
|
-
|
|
976
|
-
it "sets the IdentiesOnly option if :keys option is given" do
|
|
977
|
-
options[:keys] = ["yep"]
|
|
978
|
-
|
|
979
|
-
args.must_match regexify(" -o IdentitiesOnly=yes ")
|
|
980
|
-
end
|
|
981
|
-
|
|
982
|
-
it "sets the LogLevel option to VERBOSE if logger is set to debug" do
|
|
983
|
-
logger.level = ::Logger::DEBUG
|
|
984
|
-
options[:logger] = logger
|
|
985
|
-
|
|
986
|
-
args.must_match regexify(" -o LogLevel=VERBOSE ")
|
|
987
|
-
end
|
|
988
|
-
|
|
989
|
-
it "sets the LogLevel option to ERROR if logger is not set to debug" do
|
|
990
|
-
logger.level = ::Logger::INFO
|
|
991
|
-
options[:logger] = logger
|
|
992
|
-
|
|
993
|
-
args.must_match regexify(" -o LogLevel=ERROR ")
|
|
994
|
-
end
|
|
995
|
-
|
|
996
|
-
it "won't set the ForwardAgent option by default" do
|
|
997
|
-
args.wont_match regexify(" -o ForwardAgent=")
|
|
998
|
-
end
|
|
999
|
-
|
|
1000
|
-
it "sets the ForwardAgent option to yes if truthy" do
|
|
1001
|
-
options[:forward_agent] = "yep"
|
|
1002
|
-
|
|
1003
|
-
args.must_match regexify(" -o ForwardAgent=yes")
|
|
1004
|
-
end
|
|
1005
|
-
|
|
1006
|
-
it "sets the ForwardAgent option to no if falsey" do
|
|
1007
|
-
options[:forward_agent] = false
|
|
1008
|
-
|
|
1009
|
-
args.must_match regexify(" -o ForwardAgent=no")
|
|
1010
|
-
end
|
|
1011
|
-
|
|
1012
|
-
it "won't add any SSH keys by default" do
|
|
1013
|
-
args.wont_match regexify(" -i ")
|
|
1014
|
-
end
|
|
1015
|
-
|
|
1016
|
-
it "sets SSH keys options if given" do
|
|
1017
|
-
options[:keys] = %w{one two}
|
|
1018
|
-
|
|
1019
|
-
args.must_match regexify(" -i one ")
|
|
1020
|
-
args.must_match regexify(" -i two ")
|
|
1021
|
-
end
|
|
1022
|
-
|
|
1023
|
-
it "sets the port option to 22 by default" do
|
|
1024
|
-
args.must_match regexify(" -p 22 ")
|
|
1025
|
-
end
|
|
1026
|
-
|
|
1027
|
-
it "sets the port option" do
|
|
1028
|
-
options[:port] = 1234
|
|
1029
|
-
|
|
1030
|
-
args.must_match regexify(" -p 1234 ")
|
|
1031
|
-
end
|
|
1032
|
-
end
|
|
1033
|
-
|
|
1034
|
-
describe "#upload" do
|
|
1035
|
-
describe "for a file" do
|
|
1036
|
-
let(:content) { "a" * 1234 }
|
|
1037
|
-
|
|
1038
|
-
let(:src) do
|
|
1039
|
-
file = Tempfile.new("file")
|
|
1040
|
-
file.write("a" * 1234)
|
|
1041
|
-
file.close
|
|
1042
|
-
FileUtils.chmod(0755, file.path)
|
|
1043
|
-
file
|
|
1044
|
-
end
|
|
1045
|
-
|
|
1046
|
-
before do
|
|
1047
|
-
expect_scp_session("-t /tmp/remote") do |channel|
|
|
1048
|
-
file_mode = running_tests_on_windows? ? 0644 : 0755
|
|
1049
|
-
channel.gets_data("\0")
|
|
1050
|
-
channel.sends_data("C#{padded_octal_string(file_mode)} 1234 #{File.basename(src.path)}\n")
|
|
1051
|
-
channel.gets_data("\0")
|
|
1052
|
-
channel.sends_data("a" * 1234)
|
|
1053
|
-
channel.sends_data("\0")
|
|
1054
|
-
channel.gets_data("\0")
|
|
1055
|
-
end
|
|
1056
|
-
end
|
|
1057
|
-
|
|
1058
|
-
after do
|
|
1059
|
-
src.unlink
|
|
1060
|
-
end
|
|
1061
|
-
|
|
1062
|
-
it "uploads a file to remote over scp" do
|
|
1063
|
-
assert_scripted do
|
|
1064
|
-
connection.upload(src.path, "/tmp/remote")
|
|
1065
|
-
end
|
|
1066
|
-
end
|
|
1067
|
-
end
|
|
1068
|
-
|
|
1069
|
-
describe "for a path" do
|
|
1070
|
-
before do
|
|
1071
|
-
@dir = Dir.mktmpdir("local")
|
|
1072
|
-
|
|
1073
|
-
# Since File.chmod is a NOOP on Windows
|
|
1074
|
-
@tmp_dir_mode = running_tests_on_windows? ? 0755 : 0700
|
|
1075
|
-
@alpha_file_mode = running_tests_on_windows? ? 0644 : 0644
|
|
1076
|
-
@beta_file_mode = running_tests_on_windows? ? 0444 : 0555
|
|
1077
|
-
|
|
1078
|
-
FileUtils.chmod(0700, @dir)
|
|
1079
|
-
File.open("#{@dir}/alpha", "wb") { |f| f.write("alpha-contents\n") }
|
|
1080
|
-
FileUtils.chmod(0644, "#{@dir}/alpha")
|
|
1081
|
-
FileUtils.mkdir_p("#{@dir}/subdir")
|
|
1082
|
-
FileUtils.chmod(0755, "#{@dir}/subdir")
|
|
1083
|
-
File.open("#{@dir}/subdir/beta", "wb") { |f| f.write("beta-contents\n") }
|
|
1084
|
-
FileUtils.chmod(0555, "#{@dir}/subdir/beta")
|
|
1085
|
-
File.open("#{@dir}/zulu", "wb") { |f| f.write("zulu-contents\n") }
|
|
1086
|
-
FileUtils.chmod(0444, "#{@dir}/zulu")
|
|
1087
|
-
|
|
1088
|
-
expect_scp_session("-t -r /tmp/remote") do |channel|
|
|
1089
|
-
channel.gets_data("\0")
|
|
1090
|
-
channel.sends_data("D#{padded_octal_string(@tmp_dir_mode)} 0 #{File.basename(@dir)}\n")
|
|
1091
|
-
channel.gets_data("\0")
|
|
1092
|
-
channel.sends_data("C#{padded_octal_string(@alpha_file_mode)} 15 alpha\n")
|
|
1093
|
-
channel.gets_data("\0")
|
|
1094
|
-
channel.sends_data("alpha-contents\n")
|
|
1095
|
-
channel.sends_data("\0")
|
|
1096
|
-
channel.gets_data("\0")
|
|
1097
|
-
channel.sends_data("D0755 0 subdir\n")
|
|
1098
|
-
channel.gets_data("\0")
|
|
1099
|
-
channel.sends_data("C#{padded_octal_string(@beta_file_mode)} 14 beta\n")
|
|
1100
|
-
channel.gets_data("\0")
|
|
1101
|
-
channel.sends_data("beta-contents\n")
|
|
1102
|
-
channel.sends_data("\0")
|
|
1103
|
-
channel.gets_data("\0")
|
|
1104
|
-
channel.sends_data("E\n")
|
|
1105
|
-
channel.gets_data("\0")
|
|
1106
|
-
channel.sends_data("C0444 14 zulu\n")
|
|
1107
|
-
channel.gets_data("\0")
|
|
1108
|
-
channel.sends_data("zulu-contents\n")
|
|
1109
|
-
channel.sends_data("\0")
|
|
1110
|
-
channel.gets_data("\0")
|
|
1111
|
-
channel.sends_data("E\n")
|
|
1112
|
-
channel.gets_data("\0")
|
|
1113
|
-
end
|
|
1114
|
-
end
|
|
1115
|
-
|
|
1116
|
-
after do
|
|
1117
|
-
FileUtils.remove_entry_secure(@dir)
|
|
1118
|
-
end
|
|
1119
|
-
|
|
1120
|
-
it "uploads a file to remote over scp" do
|
|
1121
|
-
with_sorted_dir_entries do
|
|
1122
|
-
assert_scripted { connection.upload(@dir, "/tmp/remote") }
|
|
1123
|
-
end
|
|
1124
|
-
end
|
|
1125
|
-
end
|
|
1126
|
-
|
|
1127
|
-
describe "for a failed upload" do
|
|
1128
|
-
let(:conn) { mock("session") }
|
|
1129
|
-
|
|
1130
|
-
before do
|
|
1131
|
-
Net::SSH.stubs(:start).returns(conn)
|
|
1132
|
-
end
|
|
1133
|
-
|
|
1134
|
-
it "raises SshFailed when an SSH exception is raised" do
|
|
1135
|
-
conn.stubs(:scp).raises(Net::SSH::Exception)
|
|
1136
|
-
|
|
1137
|
-
e = proc do
|
|
1138
|
-
connection.upload("nope", "fail")
|
|
1139
|
-
end.must_raise Kitchen::Transport::SshFailed
|
|
1140
|
-
e.message.must_match regexify("SCP upload failed")
|
|
1141
|
-
end
|
|
1142
|
-
end
|
|
1143
|
-
end
|
|
1144
|
-
|
|
1145
|
-
describe "#download" do
|
|
1146
|
-
let(:conn) { mock("session") }
|
|
1147
|
-
let(:scp) { mock("scp") }
|
|
1148
|
-
|
|
1149
|
-
before do
|
|
1150
|
-
Net::SSH.stubs(:start).returns(conn)
|
|
1151
|
-
conn.stubs(:scp).returns(scp)
|
|
1152
|
-
@local_parent = Dir.mktmpdir("dir")
|
|
1153
|
-
@local = File.join(@local_parent, "local")
|
|
1154
|
-
end
|
|
1155
|
-
|
|
1156
|
-
after do
|
|
1157
|
-
FileUtils.remove_entry_secure(@local_parent)
|
|
1158
|
-
end
|
|
1159
|
-
|
|
1160
|
-
describe "for a file" do
|
|
1161
|
-
it "downloads a file from a remote over scp" do
|
|
1162
|
-
FileUtils.expects(:mkdir_p).with(@local_parent)
|
|
1163
|
-
scp.expects(:download!).with("/remote", @local)
|
|
1164
|
-
|
|
1165
|
-
connection.download("/remote", @local)
|
|
1166
|
-
end
|
|
1167
|
-
end
|
|
1168
|
-
|
|
1169
|
-
describe "for a list of files" do
|
|
1170
|
-
it "downloads the files from a remote over scp" do
|
|
1171
|
-
FileUtils.expects(:mkdir_p).with(@local_parent)
|
|
1172
|
-
scp.expects(:download!).with("/remote-1", @local)
|
|
1173
|
-
scp.expects(:download!).with("/remote-2", @local)
|
|
1174
|
-
|
|
1175
|
-
connection.download(["/remote-1", "/remote-2"], @local)
|
|
1176
|
-
end
|
|
1177
|
-
end
|
|
1178
|
-
|
|
1179
|
-
describe "for a directory" do
|
|
1180
|
-
it "downloads the directory from a remote over scp" do
|
|
1181
|
-
FileUtils.expects(:mkdir_p).with(@local_parent)
|
|
1182
|
-
scp.expects(:download!).with("/remote-dir", @local).raises(Net::SCP::Error)
|
|
1183
|
-
scp.expects(:download!).with("/remote-dir", @local, recursive: true)
|
|
1184
|
-
|
|
1185
|
-
connection.download("/remote-dir", @local)
|
|
1186
|
-
end
|
|
1187
|
-
end
|
|
1188
|
-
|
|
1189
|
-
describe "for a file that does not exist" do
|
|
1190
|
-
it "logs a warning" do
|
|
1191
|
-
FileUtils.expects(:mkdir_p).with(@local_parent)
|
|
1192
|
-
scp.expects(:download!).with("/remote", @local).raises(Net::SCP::Error)
|
|
1193
|
-
scp.expects(:download!).with("/remote", @local, recursive: true)
|
|
1194
|
-
.raises(Net::SCP::Error)
|
|
1195
|
-
|
|
1196
|
-
connection.download("/remote", @local)
|
|
1197
|
-
|
|
1198
|
-
logged_output.string.lines.count do |l|
|
|
1199
|
-
l =~ warn_line_with(
|
|
1200
|
-
"SCP download failed for file or directory '/remote', perhaps it does not exist?"
|
|
1201
|
-
)
|
|
1202
|
-
end.must_equal 1
|
|
1203
|
-
end
|
|
1204
|
-
end
|
|
1205
|
-
|
|
1206
|
-
describe "for a failed download" do
|
|
1207
|
-
it "raises SshFailed when an SSH exception is raised" do
|
|
1208
|
-
conn.stubs(:scp).raises(Net::SSH::Exception)
|
|
1209
|
-
|
|
1210
|
-
e = proc do
|
|
1211
|
-
connection.download("nope", "fail")
|
|
1212
|
-
end.must_raise Kitchen::Transport::SshFailed
|
|
1213
|
-
e.message.must_match regexify("SCP download failed")
|
|
1214
|
-
end
|
|
1215
|
-
end
|
|
1216
|
-
end
|
|
1217
|
-
|
|
1218
|
-
describe "#wait_until_ready" do
|
|
1219
|
-
before do
|
|
1220
|
-
options[:max_wait_until_ready] = 300
|
|
1221
|
-
connection.stubs(:sleep)
|
|
1222
|
-
end
|
|
1223
|
-
|
|
1224
|
-
describe "when failing to connect" do
|
|
1225
|
-
before do
|
|
1226
|
-
Net::SSH.stubs(:start).raises(Errno::ECONNREFUSED)
|
|
1227
|
-
end
|
|
1228
|
-
|
|
1229
|
-
it "attempts to connect :max_wait_until_ready / 3 times if failing" do
|
|
1230
|
-
begin
|
|
1231
|
-
connection.wait_until_ready
|
|
1232
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
1233
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
1234
|
-
end
|
|
1235
|
-
|
|
1236
|
-
logged_output.string.lines.count do |l|
|
|
1237
|
-
l =~ info_line_with(
|
|
1238
|
-
"Waiting for SSH service on foo:22, retrying in 3 seconds")
|
|
1239
|
-
end.must_equal((300 / 3) - 1)
|
|
1240
|
-
logged_output.string.lines.count do |l|
|
|
1241
|
-
l =~ debug_line_with("[SSH] connection failed ")
|
|
1242
|
-
end.must_equal((300 / 3) - 1)
|
|
1243
|
-
logged_output.string.lines.count do |l|
|
|
1244
|
-
l =~ warn_line_with("[SSH] connection failed, terminating ")
|
|
1245
|
-
end.must_equal 1
|
|
1246
|
-
end
|
|
1247
|
-
|
|
1248
|
-
it "sleeps for 3 seconds between retries" do
|
|
1249
|
-
connection.unstub(:sleep)
|
|
1250
|
-
connection.expects(:sleep).with(3).times((300 / 3) - 1)
|
|
1251
|
-
|
|
1252
|
-
begin
|
|
1253
|
-
connection.wait_until_ready
|
|
1254
|
-
rescue # rubocop:disable Lint/HandleExceptions
|
|
1255
|
-
# the raise is not what is being tested here, rather its side-effect
|
|
1256
|
-
end
|
|
1257
|
-
end
|
|
1258
|
-
end
|
|
1259
|
-
|
|
1260
|
-
describe "when connection is successful" do
|
|
1261
|
-
before do
|
|
1262
|
-
story do |script|
|
|
1263
|
-
channel = script.opens_channel
|
|
1264
|
-
channel.sends_request_pty
|
|
1265
|
-
channel.sends_exec("echo '[SSH] Established'")
|
|
1266
|
-
channel.gets_data("[SSH] Established\n")
|
|
1267
|
-
channel.gets_exit_status(0)
|
|
1268
|
-
channel.gets_close
|
|
1269
|
-
channel.sends_close
|
|
1270
|
-
end
|
|
1271
|
-
end
|
|
1272
|
-
|
|
1273
|
-
it "executes an ping command string to ensure working" do
|
|
1274
|
-
assert_scripted { connection.wait_until_ready }
|
|
1275
|
-
end
|
|
1276
|
-
|
|
1277
|
-
it "logger captures stdout" do
|
|
1278
|
-
assert_scripted { connection.wait_until_ready }
|
|
1279
|
-
|
|
1280
|
-
logged_output.string.must_match(/^\[SSH\] Established$/)
|
|
1281
|
-
end
|
|
1282
|
-
end
|
|
1283
|
-
end
|
|
1284
|
-
|
|
1285
|
-
def expect_scp_session(args)
|
|
1286
|
-
story do |script|
|
|
1287
|
-
channel = script.opens_channel
|
|
1288
|
-
channel.sends_exec("scp #{args}")
|
|
1289
|
-
yield channel if block_given?
|
|
1290
|
-
channel.sends_eof
|
|
1291
|
-
channel.gets_exit_status(0)
|
|
1292
|
-
channel.gets_eof
|
|
1293
|
-
channel.gets_close
|
|
1294
|
-
channel.sends_close
|
|
1295
|
-
end
|
|
1296
|
-
end
|
|
1297
|
-
|
|
1298
|
-
def debug_line(msg)
|
|
1299
|
-
/^D, .* : #{Regexp.escape(msg)}$/
|
|
1300
|
-
end
|
|
1301
|
-
|
|
1302
|
-
def debug_line_with(msg)
|
|
1303
|
-
/^D, .* : #{Regexp.escape(msg)}/
|
|
1304
|
-
end
|
|
1305
|
-
|
|
1306
|
-
def info_line_with(msg)
|
|
1307
|
-
/^I, .* : #{Regexp.escape(msg)}/
|
|
1308
|
-
end
|
|
1309
|
-
|
|
1310
|
-
def regexify(string)
|
|
1311
|
-
Regexp.new(Regexp.escape(string))
|
|
1312
|
-
end
|
|
1313
|
-
|
|
1314
|
-
def warn_line_with(msg)
|
|
1315
|
-
/^W, .* : #{Regexp.escape(msg)}/
|
|
1316
|
-
end
|
|
1317
|
-
end
|