ridley 0.10.2 → 0.11.0.rc1

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.
Files changed (85) hide show
  1. data/README.md +147 -216
  2. data/lib/ridley.rb +2 -0
  3. data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +21 -25
  4. data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +29 -34
  5. data/lib/ridley/bootstrapper.rb +2 -2
  6. data/lib/ridley/bootstrapper/context.rb +5 -5
  7. data/lib/ridley/chef.rb +0 -1
  8. data/lib/ridley/chef/cookbook.rb +0 -9
  9. data/lib/ridley/chef_object.rb +128 -0
  10. data/lib/ridley/chef_objects.rb +3 -0
  11. data/lib/ridley/chef_objects/client_object.rb +55 -0
  12. data/lib/ridley/chef_objects/cookbook_object.rb +190 -0
  13. data/lib/ridley/chef_objects/data_bag_item_obect.rb +104 -0
  14. data/lib/ridley/chef_objects/data_bag_object.rb +31 -0
  15. data/lib/ridley/chef_objects/environment_object.rb +59 -0
  16. data/lib/ridley/chef_objects/node_object.rb +161 -0
  17. data/lib/ridley/chef_objects/role_object.rb +62 -0
  18. data/lib/ridley/chef_objects/sandbox_object.rb +58 -0
  19. data/lib/ridley/client.rb +76 -45
  20. data/lib/ridley/connection.rb +1 -1
  21. data/lib/ridley/errors.rb +8 -1
  22. data/lib/ridley/host_connector.rb +26 -6
  23. data/lib/ridley/host_connector/ssh.rb +3 -3
  24. data/lib/ridley/host_connector/ssh/worker.rb +7 -9
  25. data/lib/ridley/host_connector/winrm/worker.rb +4 -5
  26. data/lib/ridley/mixin/bootstrap_binding.rb +1 -12
  27. data/lib/ridley/resource.rb +51 -171
  28. data/lib/ridley/resources/client_resource.rb +18 -68
  29. data/lib/ridley/resources/cookbook_resource.rb +181 -381
  30. data/lib/ridley/resources/data_bag_item_resource.rb +55 -161
  31. data/lib/ridley/resources/data_bag_resource.rb +20 -61
  32. data/lib/ridley/resources/environment_resource.rb +9 -64
  33. data/lib/ridley/resources/node_resource.rb +135 -311
  34. data/lib/ridley/resources/role_resource.rb +1 -57
  35. data/lib/ridley/resources/sandbox_resource.rb +80 -65
  36. data/lib/ridley/resources/search_resource.rb +99 -0
  37. data/lib/ridley/sandbox_uploader.rb +12 -52
  38. data/lib/ridley/version.rb +1 -1
  39. data/spec/acceptance/bootstrapping_spec.rb +1 -1
  40. data/spec/acceptance/client_resource_spec.rb +15 -37
  41. data/spec/acceptance/data_bag_item_resource_spec.rb +8 -14
  42. data/spec/acceptance/data_bag_resource_spec.rb +1 -1
  43. data/spec/acceptance/environment_resource_spec.rb +13 -22
  44. data/spec/acceptance/node_resource_spec.rb +10 -29
  45. data/spec/acceptance/role_resource_spec.rb +14 -13
  46. data/spec/acceptance/sandbox_resource_spec.rb +2 -2
  47. data/spec/support/shared_examples/ridley_resource.rb +2 -23
  48. data/spec/unit/ridley/bootstrap_bindings/unix_template_binding_spec.rb +3 -4
  49. data/spec/unit/ridley/bootstrap_bindings/windows_template_binding_spec.rb +3 -5
  50. data/spec/unit/ridley/bootstrapper/context_spec.rb +2 -3
  51. data/spec/unit/ridley/bootstrapper_spec.rb +1 -1
  52. data/spec/unit/ridley/chef_object_spec.rb +240 -0
  53. data/spec/unit/ridley/chef_objects/client_object_spec.rb +11 -0
  54. data/spec/unit/ridley/chef_objects/cookbook_object_spec.rb +93 -0
  55. data/spec/unit/ridley/chef_objects/data_bag_item_object_spec.rb +74 -0
  56. data/spec/unit/ridley/chef_objects/data_bag_object_spec.rb +9 -0
  57. data/spec/unit/ridley/chef_objects/environment_object_spec.rb +57 -0
  58. data/spec/unit/ridley/chef_objects/node_object_spec.rb +252 -0
  59. data/spec/unit/ridley/chef_objects/role_object_spec.rb +57 -0
  60. data/spec/unit/ridley/chef_objects/sandbox_object_spec.rb +66 -0
  61. data/spec/unit/ridley/client_spec.rb +51 -51
  62. data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +4 -4
  63. data/spec/unit/ridley/host_connector/ssh_spec.rb +26 -24
  64. data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +3 -4
  65. data/spec/unit/ridley/host_connector/winrm_spec.rb +4 -4
  66. data/spec/unit/ridley/host_connector_spec.rb +40 -3
  67. data/spec/unit/ridley/mixin/bootstrap_binding_spec.rb +1 -1
  68. data/spec/unit/ridley/resource_spec.rb +81 -109
  69. data/spec/unit/ridley/resources/client_resource_spec.rb +18 -33
  70. data/spec/unit/ridley/resources/cookbook_resource_spec.rb +56 -230
  71. data/spec/unit/ridley/resources/data_bag_item_resource_spec.rb +2 -57
  72. data/spec/unit/ridley/resources/data_bag_resource_spec.rb +12 -7
  73. data/spec/unit/ridley/resources/environment_resource_spec.rb +10 -118
  74. data/spec/unit/ridley/resources/node_resource_spec.rb +83 -394
  75. data/spec/unit/ridley/resources/role_resource_spec.rb +2 -56
  76. data/spec/unit/ridley/resources/sandbox_resource_spec.rb +139 -136
  77. data/spec/unit/ridley/resources/search_resource_spec.rb +234 -0
  78. data/spec/unit/ridley/sandbox_uploader_spec.rb +13 -58
  79. metadata +36 -17
  80. data/lib/ridley/chef/chefignore.rb +0 -76
  81. data/lib/ridley/resources/encrypted_data_bag_item_resource.rb +0 -55
  82. data/lib/ridley/resources/search.rb +0 -101
  83. data/spec/fixtures/chefignore +0 -8
  84. data/spec/unit/ridley/chef/chefignore_spec.rb +0 -40
  85. data/spec/unit/ridley/resources/search_spec.rb +0 -221
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ridley::SandboxObject do
4
+ let(:resource) { double('chef-resource') }
5
+
6
+ subject do
7
+ described_class.new(double('registry'),
8
+ "uri" => "https://api.opscode.com/organizations/vialstudios/sandboxes/bd091b150b0a4578b97771af6abf3e05",
9
+ "checksums" => {
10
+ "385ea5490c86570c7de71070bce9384a" => {
11
+ "url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
12
+ "needs_upload" => true
13
+ },
14
+ "f6f73175e979bd90af6184ec277f760c" => {
15
+ "url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
16
+ "needs_upload" => true
17
+ },
18
+ "2e03dd7e5b2e6c8eab1cf41ac61396d5" => {
19
+ "url" => "https://s3.amazonaws.com/opscode-platform-production-data/organization",
20
+ "needs_upload" => true
21
+ },
22
+ },
23
+ "sandbox_id" => "bd091b150b0a4578b97771af6abf3e05"
24
+ )
25
+ end
26
+
27
+ before { subject.stub(resource: resource) }
28
+
29
+ describe "#checksums" do
30
+ pending
31
+ end
32
+
33
+ describe "#commit" do
34
+ let(:response) { { is_completed: nil} }
35
+ before { resource.should_receive(:commit).with(subject).and_return(response) }
36
+
37
+ context "when the commit is successful" do
38
+ before { response[:is_completed] = true }
39
+
40
+ it "has an 'is_completed' value of true" do
41
+ subject.commit
42
+
43
+ subject.is_completed.should be_true
44
+ end
45
+ end
46
+
47
+ context "when the commit is a failure" do
48
+ before { response[:is_completed] = false }
49
+
50
+ it "has an 'is_completed' value of false" do
51
+ subject.commit
52
+
53
+ subject.is_completed.should be_false
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#upload" do
59
+ it "delegates to resource#upload" do
60
+ checksums = double('checksums')
61
+ resource.should_receive(:upload).with(subject, checksums)
62
+
63
+ subject.upload(checksums)
64
+ end
65
+ end
66
+ end
@@ -24,124 +24,124 @@ describe Ridley::Client do
24
24
  end
25
25
 
26
26
  describe "ClassMethods" do
27
- subject { described_class }
27
+ let(:options) do
28
+ {
29
+ server_url: "https://api.opscode.com/some_path",
30
+ client_name: client_name,
31
+ client_key: client_key
32
+ }
33
+ end
28
34
 
29
35
  describe "::initialize" do
30
- let(:server_url) { "https://api.opscode.com/some_path" }
36
+ subject { described_class.new(options) }
31
37
 
32
38
  describe "parsing the 'server_url' option" do
33
- before(:each) do
34
- @conn = subject.new(
35
- server_url: server_url,
36
- client_name: client_name,
37
- client_key: client_key,
38
- )
39
- end
40
-
41
- it "assigns a 'host' attribute from the given 'server_url' option" do
42
- @conn.host.should eql("api.opscode.com")
43
- end
44
-
45
- it "assigns a 'scheme' attribute from the given 'server_url' option" do
46
- @conn.scheme.should eql("https")
47
- end
48
-
49
- it "sets a 'path_prefix' to the root of the given 'server_url' option" do
50
- @conn.path_prefix.should eql("/")
51
- end
39
+ its(:host) { should eql("api.opscode.com") }
40
+ its(:scheme) { should eql("https") }
41
+ its(:path_prefix) { should eql("/") }
52
42
  end
53
43
 
54
44
  describe "with a server_url containing an organization" do
55
- before(:each) do
56
- @conn = subject.new(
57
- server_url: "#{server_url}/organizations/#{organization}",
58
- client_name: client_name,
59
- client_key: client_key
60
- )
45
+ before do
46
+ options[:server_url] = "#{server_url}/organizations/#{organization}"
61
47
  end
62
48
 
63
49
  it "gets the host data from the server_url" do
64
- @conn.host.should eql("api.opscode.com")
65
- @conn.scheme.should eql("https")
50
+ subject.host.should eql("api.opscode.com")
51
+ subject.scheme.should eql("https")
66
52
  end
67
53
 
68
- it "assigns the value of the 'organization' option to an 'organization' attribute" do
69
- @conn.connection.organization.should eql(organization)
54
+ it "takes the organization out of the server_url and assigns it to the organization reader" do
55
+ subject.organization.should eql(organization)
70
56
  end
71
57
 
72
58
  it "sets the 'path_prefix' of the connection the organization sub URI" do
73
- @conn.path_prefix.should eql("/organizations/#{organization}")
59
+ subject.path_prefix.should eql("/organizations/#{organization}")
74
60
  end
75
61
  end
76
62
 
77
63
  it "raises 'ArgumentError' if a value for server_url is not given" do
78
- lambda {
79
- subject.new(
64
+ expect {
65
+ described_class.new(
80
66
  client_name: client_name,
81
67
  client_key: client_key
82
68
  )
83
- }.should raise_error(ArgumentError, "Missing required option(s): 'server_url'")
69
+ }.to raise_error(ArgumentError, "Missing required option(s): 'server_url'")
84
70
  end
85
71
 
86
72
  it "raises if a value for client_name is not given" do
87
- lambda {
88
- subject.new(
73
+ expect {
74
+ described_class.new(
89
75
  server_url: server_url,
90
76
  client_key: client_key
91
77
  )
92
- }.should raise_error(ArgumentError, "Missing required option(s): 'client_name'")
78
+ }.to raise_error(ArgumentError, "Missing required option(s): 'client_name'")
93
79
  end
94
80
 
95
81
  it "raises if a value for client_key is not given" do
96
- lambda {
97
- subject.new(
82
+ expect {
83
+ described_class.new(
98
84
  server_url: server_url,
99
85
  client_name: client_name
100
86
  )
101
- }.should raise_error(ArgumentError, "Missing required option(s): 'client_key'")
87
+ }.to raise_error(ArgumentError, "Missing required option(s): 'client_key'")
102
88
  end
103
89
 
104
90
  it "raises a ClientKeyFileNotFound if the filepath for client_key is not found" do
105
91
  config[:client_key] = "/tmp/nofile.xxsa"
106
92
 
107
- lambda {
108
- subject.new(config)
109
- }.should raise_error(Ridley::Errors::ClientKeyFileNotFound)
93
+ expect {
94
+ described_class.new(config)
95
+ }.to raise_error(Ridley::Errors::ClientKeyFileNotFound)
110
96
  end
111
97
 
112
98
  it "expands the path of the client_key" do
113
99
  config[:client_key] = "~/"
114
100
 
115
- subject.new(config).client_key.should_not == "~/"
101
+ described_class.new(config).client_key.should_not == "~/"
116
102
  end
117
103
 
118
104
  it "assigns a 'ssh' attribute from the given 'ssh' option" do
119
- subject.new(config).ssh.should eql({user: "reset", password: "password1", port: "222"})
105
+ described_class.new(config).ssh.should eql({user: "reset", password: "password1", port: "222"})
120
106
  end
121
107
 
122
108
  it "assigns a 'winrm' attribute from the given 'winrm' option" do
123
- subject.new(config).winrm.should eql({user: "reset", password: "password2", port: "5986"})
109
+ described_class.new(config).winrm.should eql({user: "reset", password: "password2", port: "5986"})
124
110
  end
125
111
 
126
112
  it "assigns a 'chef_version' attribute from the given 'chef_version' option" do
127
- subject.new(config).chef_version.should eql("10.24.0-01")
113
+ described_class.new(config).chef_version.should eql("10.24.0-01")
128
114
  end
129
115
  end
130
116
 
131
117
  describe "::open" do
132
118
  it "raises a LocalJumpError if no block is given" do
133
119
  lambda {
134
- subject.open(config)
120
+ described_class.open(config)
135
121
  }.should raise_error(LocalJumpError)
136
122
  end
137
123
  end
138
124
  end
139
125
 
140
- subject do
141
- described_class.new(config)
126
+ let(:instance) { described_class.new(config) }
127
+
128
+ describe "#node" do
129
+ subject { instance.node }
130
+
131
+ it { should be_a(Ridley::NodeResource) }
132
+
133
+ its(:server_url) { should eql(config[:server_url]) }
134
+ its(:validator_path) { should eql(config[:validator_path]) }
135
+ its(:validator_client) { should eql(config[:validator_client]) }
136
+ its(:encrypted_data_bag_secret) { should eql(instance.encrypted_data_bag_secret) }
137
+ its(:ssh) { should eql(config[:ssh]) }
138
+ its(:winrm) { should eql(config[:winrm]) }
139
+ its(:chef_version) { should eql(config[:chef_version]) }
142
140
  end
143
141
 
144
142
  describe "#encrypted_data_bag_secret" do
143
+ subject { instance }
144
+
145
145
  it "returns a string" do
146
146
  subject.encrypted_data_bag_secret.should be_a(String)
147
147
  end
@@ -6,7 +6,7 @@ describe Ridley::HostConnector::SSH::Worker do
6
6
 
7
7
  let(:host) { 'reset.riotgames.com' }
8
8
  let(:options) { {} }
9
-
9
+
10
10
  describe "#sudo" do
11
11
  subject { ssh_worker.sudo }
12
12
 
@@ -14,7 +14,7 @@ describe Ridley::HostConnector::SSH::Worker do
14
14
 
15
15
  context "with sudo" do
16
16
  let(:options) { { ssh: { sudo: true } } }
17
-
17
+
18
18
  it { should be_true }
19
19
  end
20
20
  end
@@ -35,10 +35,10 @@ describe Ridley::HostConnector::SSH::Worker do
35
35
  end
36
36
 
37
37
  describe "#put_secret" do
38
- subject(:put_secret) { ssh_worker.put_secret(encrypted_data_bag_secret_path) }
38
+ subject(:put_secret) { ssh_worker.put_secret(secret) }
39
39
  let(:encrypted_data_bag_secret_path) { fixtures_path.join("encrypted_data_bag_secret").to_s }
40
40
  let(:secret) { File.read(encrypted_data_bag_secret_path).chomp }
41
-
41
+
42
42
  it "receives a run command with echo" do
43
43
  ssh_worker.should_receive(:run).with("echo '#{secret}' > /etc/chef/encrypted_data_bag_secret; chmod 0600 /etc/chef/encrypted_data_bag_secret")
44
44
  put_secret
@@ -1,37 +1,29 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Ridley::HostConnector::SSH do
4
- let(:connection) { double('conn', ssh: { user: "vagrant", password: "vagrant" }) }
4
+ let(:resource) { double('resource') }
5
5
 
6
6
  let(:node_one) do
7
- Ridley::NodeResource.new(connection, automatic: { cloud: { public_hostname: "33.33.33.10" } })
7
+ Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.10" } })
8
8
  end
9
9
 
10
10
  let(:node_two) do
11
- Ridley::NodeResource.new(connection, automatic: { cloud: { public_hostname: "33.33.33.11" } })
11
+ Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.11" } })
12
12
  end
13
13
 
14
- describe "ClassMethods" do
15
- subject { Ridley::HostConnector::SSH }
16
-
17
- describe "::start" do
18
- let(:options) do
19
- {
20
- user: "vagrant",
21
- password: "vagrant",
22
- timeout: 1
23
- }
24
- end
25
-
26
- it "evaluates within the context of a new SSH and returns the last item in the block" do
27
- result = subject.start([node_one, node_two], options) do |ssh|
28
- ssh.run("ls")
29
- end
14
+ let(:options) do
15
+ {
16
+ user: "vagrant",
17
+ password: "vagrant",
18
+ timeout: 1
19
+ }
20
+ end
30
21
 
31
- result.should be_a(Ridley::HostConnector::ResponseSet)
32
- end
22
+ describe "ClassMethods" do
23
+ subject { described_class }
33
24
 
34
- it "raises a LocalJumpError if a block is not provided" do
25
+ describe "::start" do
26
+ it "raises a LocalJumpError if a block is not provided" do
35
27
  expect {
36
28
  subject.start([node_one, node_two], options)
37
29
  }.to raise_error(LocalJumpError)
@@ -39,10 +31,20 @@ describe Ridley::HostConnector::SSH do
39
31
  end
40
32
  end
41
33
 
42
- subject { Ridley::HostConnector::SSH.new([node_one, node_two], ssh: {user: "vagrant", password: "vagrant", timeout: 1}) }
34
+ subject do
35
+ Ridley::HostConnector::SSH.new([node_one, node_two], ssh: { user: "vagrant", password: "vagrant", timeout: 1 })
36
+ end
43
37
 
44
38
  describe "#run" do
45
- it "returns an HostConnector::ResponseSet" do
39
+ let(:worker) { double('worker', terminate: nil) }
40
+ let(:response) { Ridley::HostConnector::Response.new("host") }
41
+ before { Ridley::HostConnector::SSH::Worker.stub(:new).and_return(worker) }
42
+
43
+ before do
44
+ worker.stub_chain(:future, :run).and_return(double(value: [:ok, response]))
45
+ end
46
+
47
+ it "returns an SSH::ResponseSet" do
46
48
  subject.run("ls").should be_a(Ridley::HostConnector::ResponseSet)
47
49
  end
48
50
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Ridley::HostConnector::WinRM::Worker do
4
4
  subject { winrm_worker }
5
5
  let(:winrm_worker) { described_class.new(host, options) }
6
- let(:host) { 'reset.riotgames.com' }
6
+ let(:host) { 'reset.riotgames.com' }
7
7
  let(:options) { {} }
8
8
 
9
9
  before do
@@ -35,7 +35,7 @@ describe Ridley::HostConnector::WinRM::Worker do
35
35
  let(:command_uploader_stub) { double('CommandUploader') }
36
36
 
37
37
  it { should eq(command) }
38
-
38
+
39
39
  context "when a command is more than 2047 characters" do
40
40
  let(:command) { "a" * 2048 }
41
41
 
@@ -62,8 +62,7 @@ describe Ridley::HostConnector::WinRM::Worker do
62
62
  end
63
63
 
64
64
  describe "#put_secret" do
65
- subject(:put_secret) { winrm_worker.put_secret(encrypted_data_bag_secret_path) }
66
-
65
+ subject(:put_secret) { winrm_worker.put_secret(secret) }
67
66
  let(:encrypted_data_bag_secret_path) { fixtures_path.join("encrypted_data_bag_secret").to_s }
68
67
  let(:secret) { File.read(encrypted_data_bag_secret_path).chomp }
69
68
 
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Ridley::HostConnector::WinRM do
4
- let(:connection) { double('conn', ssh: { user: "vagrant", password: "vagrant" }) }
4
+ let(:resource) { double('resource') }
5
5
 
6
6
  let(:node_one) do
7
- Ridley::NodeResource.new(connection, automatic: { cloud: { public_hostname: "33.33.33.10" } })
7
+ Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.10" } })
8
8
  end
9
9
 
10
10
  let(:node_two) do
11
- Ridley::NodeResource.new(connection, automatic: { cloud: { public_hostname: "33.33.33.11" } })
11
+ Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.11" } })
12
12
  end
13
13
  let(:command_uploader) { double('command_uploader', cleanup: nil) }
14
14
 
@@ -18,7 +18,7 @@ describe Ridley::HostConnector::WinRM do
18
18
 
19
19
  describe "ClassMethods" do
20
20
  subject { Ridley::HostConnector::WinRM }
21
-
21
+
22
22
  describe "::start" do
23
23
  let(:options) do
24
24
  {
@@ -13,7 +13,44 @@ describe Ridley::HostConnector do
13
13
  described_class::DEFAULT_WINRM_PORT.should eq(5985)
14
14
  end
15
15
 
16
- describe "#connector_port_open?" do
16
+ describe "::new" do
17
+ let(:host) { "192.168.1.1" }
18
+ let(:options) do
19
+ {
20
+ ssh: {
21
+ user: "reset",
22
+ password: "lol"
23
+ },
24
+ winrm: {
25
+ user: "Administrator",
26
+ password: "secret"
27
+ }
28
+ }
29
+ end
30
+
31
+ subject { described_class.new(host, options) }
32
+
33
+ context "when the best connector is SSH" do
34
+ before do
35
+ described_class.stub(:best_connector_for).and_yield(Ridley::HostConnector::SSH)
36
+ end
37
+
38
+ it { should be_a(Ridley::HostConnector::SSH::Worker) }
39
+ its(:user) { should eq("reset") }
40
+ end
41
+
42
+ context "when the best connector is WinRM" do
43
+ before do
44
+ described_class.stub(:best_connector_for).and_yield(Ridley::HostConnector::WinRM)
45
+ end
46
+
47
+ it { should be_a(Ridley::HostConnector::WinRM::Worker) }
48
+ its(:user) { should eq("Administrator") }
49
+ its(:password) { should eq("secret") }
50
+ end
51
+ end
52
+
53
+ describe "::connector_port_open?" do
17
54
  let(:host) { "127.0.0.1" }
18
55
  let(:port) { 22 }
19
56
  let(:socket) { double(:new => true, :close => nil) }
@@ -54,7 +91,7 @@ describe Ridley::HostConnector do
54
91
  end
55
92
  end
56
93
 
57
- describe "#best_connector_for" do
94
+ describe "::best_connector_for" do
58
95
  let(:host) {"127.0.0.1"}
59
96
 
60
97
  context "when an SSH port is open" do
@@ -90,7 +127,7 @@ describe Ridley::HostConnector do
90
127
  end
91
128
  end
92
129
 
93
- describe "#parse_port_options" do
130
+ describe "::parse_port_options" do
94
131
  let(:options) do
95
132
  {
96
133
  ssh: {