derelict 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +5 -13
  2. data/.cane +2 -0
  3. data/.coveralls.yml +1 -0
  4. data/.travis.yml +13 -0
  5. data/README.md +55 -9
  6. data/Rakefile +21 -0
  7. data/derelict.gemspec +25 -1
  8. data/lib/derelict/connection/invalid.rb +14 -0
  9. data/lib/derelict/connection/not_found.rb +13 -0
  10. data/lib/derelict/connection.rb +84 -0
  11. data/lib/derelict/exception/optional_reason.rb +32 -0
  12. data/lib/derelict/exception.rb +3 -2
  13. data/lib/derelict/instance/command_failed.rb +28 -0
  14. data/lib/derelict/instance/invalid.rb +11 -11
  15. data/lib/derelict/instance/missing_binary.rb +13 -0
  16. data/lib/derelict/instance/non_directory.rb +10 -8
  17. data/lib/derelict/instance/not_found.rb +10 -8
  18. data/lib/derelict/instance.rb +105 -33
  19. data/lib/derelict/parser/status/invalid_format.rb +16 -0
  20. data/lib/derelict/parser/status.rb +89 -0
  21. data/lib/derelict/parser/version/invalid_format.rb +16 -0
  22. data/lib/derelict/parser/version.rb +28 -0
  23. data/lib/derelict/parser.rb +25 -0
  24. data/lib/derelict/utils/logger/array_outputter.rb +43 -0
  25. data/lib/derelict/utils/logger/invalid_type.rb +15 -0
  26. data/lib/derelict/utils/logger/raw_formatter.rb +12 -0
  27. data/lib/derelict/utils/logger.rb +51 -0
  28. data/lib/derelict/utils.rb +11 -0
  29. data/lib/derelict/version.rb +2 -2
  30. data/lib/derelict/virtual_machine/invalid.rb +14 -0
  31. data/lib/derelict/virtual_machine/not_found.rb +18 -0
  32. data/lib/derelict/virtual_machine.rb +154 -0
  33. data/lib/derelict.rb +61 -14
  34. data/spec/coverage_helper.rb +16 -0
  35. data/spec/derelict/connection/invalid_spec.rb +16 -0
  36. data/spec/derelict/connection/not_found_spec.rb +13 -0
  37. data/spec/derelict/connection_spec.rb +107 -0
  38. data/spec/derelict/exception/optional_reason_spec.rb +41 -0
  39. data/spec/derelict/exception_spec.rb +11 -0
  40. data/spec/derelict/instance/command_failed_spec.rb +40 -0
  41. data/spec/derelict/instance/invalid_spec.rb +16 -0
  42. data/spec/derelict/instance/missing_binary_spec.rb +13 -0
  43. data/spec/derelict/instance/non_directory_spec.rb +13 -0
  44. data/spec/derelict/instance/not_found_spec.rb +13 -0
  45. data/spec/derelict/instance_spec.rb +226 -0
  46. data/spec/derelict/parser/status/invalid_format_spec.rb +16 -0
  47. data/spec/derelict/parser/status_spec.rb +214 -0
  48. data/spec/derelict/parser/version/invalid_format_spec.rb +16 -0
  49. data/spec/derelict/parser/version_spec.rb +31 -0
  50. data/spec/derelict/parser_spec.rb +24 -0
  51. data/spec/derelict/utils/logger/array_outputter_spec.rb +40 -0
  52. data/spec/derelict/utils/logger/invalid_type_spec.rb +13 -0
  53. data/spec/derelict/utils/logger/raw_formatter_spec.rb +17 -0
  54. data/spec/derelict/utils/logger_spec.rb +35 -0
  55. data/spec/derelict/virtual_machine/invalid_spec.rb +16 -0
  56. data/spec/derelict/virtual_machine/not_found_spec.rb +34 -0
  57. data/spec/derelict/virtual_machine_spec.rb +295 -0
  58. data/spec/derelict_spec.rb +50 -0
  59. data/spec/spec_helper.rb +28 -3
  60. data/spec/support/log_context.rb +36 -0
  61. metadata +175 -22
  62. data/lib/derelict/instance/already_active.rb +0 -9
  63. data/spec/system_spec.spec +0 -10
@@ -0,0 +1,107 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Connection do
4
+ let(:description) { "the test instance" }
5
+ let(:instance) { double("instance", :description => description) }
6
+ let(:path) { "/baz/qux" }
7
+ let(:connection) { Derelict::Connection.new instance, path }
8
+ subject { connection }
9
+
10
+ it "is autoloaded" do
11
+ should be_a Derelict::Connection
12
+ end
13
+
14
+ include_context "logged messages"
15
+ let(:expected_logs) {[
16
+ "DEBUG connection: Successfully initialized Derelict::Connection at '/baz/qux' using the test instance\n"
17
+ ]}
18
+
19
+ describe "#validate!" do
20
+ subject { connection.validate! }
21
+ let(:exists?) { double("exists?") }
22
+ before do
23
+ expect(File).to receive(:exists?).with(path).and_return(exists?)
24
+ end
25
+
26
+ context "with valid data" do
27
+ let(:exists?) { true }
28
+ it { should be connection }
29
+
30
+ include_context "logged messages"
31
+ let(:expected_logs) {[
32
+ "DEBUG connection: Successfully initialized Derelict::Connection at '/baz/qux' using the test instance\n",
33
+ "DEBUG connection: Starting validation for Derelict::Connection at '/baz/qux' using the test instance\n",
34
+ " INFO connection: Successfully validated Derelict::Connection at '/baz/qux' using the test instance\n",
35
+ ]}
36
+ end
37
+
38
+ context "with invalid data" do
39
+ let(:exists?) { false }
40
+ it "should raise NotFound" do
41
+ expect { subject }.to raise_error Derelict::Connection::NotFound
42
+ end
43
+
44
+ include_context "logged messages"
45
+ let(:expected_logs) {[
46
+ "DEBUG connection: Successfully initialized Derelict::Connection at '/baz/qux' using the test instance\n",
47
+ "DEBUG connection: Starting validation for Derelict::Connection at '/baz/qux' using the test instance\n",
48
+ ]}
49
+ end
50
+ end
51
+
52
+ describe "#execute" do
53
+ subject { connection.execute :test, "arg 1" }
54
+
55
+ it "should change current working directory first" do
56
+ expect(Dir).to receive(:chdir).with(path).and_return(:foo) # no yield
57
+ expect(instance).to_not receive(:execute)
58
+ expect(subject).to be :foo
59
+ end
60
+
61
+ it "should delegate to @instance#execute" do
62
+ expect(Dir).to receive(:chdir).with(path).and_yield
63
+ expect(instance).to receive(:execute).with(:test, "arg 1").and_return(:bar)
64
+ expect(subject).to be :bar
65
+ end
66
+
67
+ include_context "logged messages"
68
+ let(:expected_logs) {[
69
+ "DEBUG connection: Successfully initialized Derelict::Connection at '/baz/qux' using the test instance\n",
70
+ "DEBUG connection: Executing test [\"arg 1\"] on Derelict::Connection at '/baz/qux' using the test instance\n",
71
+ ]}
72
+ end
73
+
74
+ describe "#execute!" do
75
+ subject { connection.execute! :test, "arg 1" }
76
+
77
+ it "should change current working directory first" do
78
+ expect(Dir).to receive(:chdir).with(path).and_return(:foo) # no yield
79
+ expect(instance).to_not receive(:execute!)
80
+ expect(subject).to be :foo
81
+ end
82
+
83
+ it "should delegate to @instance#execute!" do
84
+ expect(Dir).to receive(:chdir).with(path).and_yield
85
+ expect(instance).to receive(:execute!).with(:test, "arg 1").and_return(:bar)
86
+ expect(subject).to be :bar
87
+ end
88
+ end
89
+
90
+ describe "#vm" do
91
+ let(:name) { :test }
92
+ let(:vm) { double("vm") }
93
+ before do
94
+ c = Derelict::VirtualMachine
95
+ expect(c).to receive(:new).with(connection, name).and_return(vm)
96
+ expect(vm).to receive(:validate!).and_return(vm)
97
+ end
98
+ subject { connection.vm name }
99
+ it { should be vm }
100
+
101
+ include_context "logged messages"
102
+ let(:expected_logs) {[
103
+ "DEBUG connection: Successfully initialized Derelict::Connection at '/baz/qux' using the test instance\n",
104
+ "DEBUG connection: Retrieving VM 'test' from Derelict::Connection at '/baz/qux' using the test instance\n",
105
+ ]}
106
+ end
107
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Exception::OptionalReason do
4
+ context "with #default_message left unimplemented" do
5
+ let(:exception) do
6
+ Class.new ::Exception do
7
+ include Derelict::Exception::OptionalReason
8
+ end
9
+ end
10
+
11
+ describe "#initialize" do
12
+ subject { exception.new reason }
13
+ let(:reason) { "test reason" }
14
+
15
+ it "should raise NotImplementedError" do
16
+ expect { subject }.to raise_error NotImplementedError
17
+ end
18
+ end
19
+ end
20
+
21
+ context "with #default_message implemented" do
22
+ let(:exception) do
23
+ Class.new ::Exception do
24
+ include Derelict::Exception::OptionalReason
25
+ private
26
+ def default_message
27
+ "test"
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#initialize" do
33
+ subject { exception.new reason }
34
+ let(:reason) { "test reason" }
35
+
36
+ it "should raise NotImplementedError" do
37
+ expect { subject }.to_not raise_error
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,11 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Exception do
4
+ it "is autoloaded" do
5
+ should be_a Derelict::Exception
6
+ end
7
+
8
+ it "inherits from ::Exception" do
9
+ should be_a ::Exception
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance::CommandFailed do
4
+ it "is autoloaded" do
5
+ should be_a Derelict::Instance::CommandFailed
6
+ end
7
+
8
+ describe "#initialize" do
9
+ let(:command) { nil }
10
+ let(:result) { nil }
11
+ subject { Derelict::Instance::CommandFailed.new command, result }
12
+
13
+ context "with no arguments" do
14
+ its(:message) { should eq "Error executing Vagrant command" }
15
+ end
16
+
17
+ context "with custom command" do
18
+ let(:command) { "my_command" }
19
+ its(:message) { should eq "Error executing Vagrant command 'my_command'" }
20
+ end
21
+
22
+ context "with custom result" do
23
+ let(:result) { double("result", :stderr => "my_stderr") }
24
+ its(:message) {
25
+ should eq "Error executing Vagrant command, STDERR output:\nmy_stderr"
26
+ }
27
+ end
28
+
29
+ context "with custom command and result" do
30
+ let(:command) { "my_command" }
31
+ let(:result) { double("result", :stderr => "my_stderr") }
32
+ its(:message) {
33
+ should eq [
34
+ "Error executing Vagrant command 'my_command', ",
35
+ "STDERR output:\nmy_stderr"
36
+ ].join
37
+ }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance::Invalid do
4
+ it "is autoloaded" do
5
+ should be_a Derelict::Instance::Invalid
6
+ end
7
+
8
+ context "when using default reason" do
9
+ its(:message) { should eq "Invalid Derelict instance" }
10
+ end
11
+
12
+ context "when using custom reason" do
13
+ subject { Derelict::Instance::Invalid.new "reason" }
14
+ its(:message) { should eq "Invalid Derelict instance: reason" }
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance::MissingBinary do
4
+ subject { Derelict::Instance::MissingBinary.new "/foo/bar" }
5
+
6
+ it "is autoloaded" do
7
+ should be_a Derelict::Instance::MissingBinary
8
+ end
9
+
10
+ its(:message) {
11
+ should eq "Invalid Derelict instance: 'vagrant' binary not found at /foo/bar"
12
+ }
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance::NonDirectory do
4
+ subject { Derelict::Instance::NonDirectory.new "/foo/bar" }
5
+
6
+ it "is autoloaded" do
7
+ should be_a Derelict::Instance::NonDirectory
8
+ end
9
+
10
+ its(:message) {
11
+ should eq "Invalid Derelict instance: expected directory, found file: /foo/bar"
12
+ }
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance::NotFound do
4
+ subject { Derelict::Instance::NotFound.new "/foo/bar" }
5
+
6
+ it "is autoloaded" do
7
+ should be_a Derelict::Instance::NotFound
8
+ end
9
+
10
+ its(:message) {
11
+ should eq "Invalid Derelict instance: directory doesn't exist: /foo/bar"
12
+ }
13
+ end
@@ -0,0 +1,226 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Instance do
4
+ let(:instance) { Derelict::Instance.new path }
5
+ let(:path) { nil }
6
+
7
+ subject { instance }
8
+
9
+ it "is autoloaded" do
10
+ should be_a Derelict::Instance
11
+ end
12
+
13
+ describe "#version" do
14
+ let(:result) { double("result", :stdout => stdout) }
15
+ let(:stdout) { double("stdout") }
16
+ let(:parser) { double("parser", :version => "the version") }
17
+ subject { instance.version }
18
+ before {
19
+ expect(instance).to receive(:execute!).with("--version").and_return(result)
20
+ expect(Derelict::Parser::Version).to receive(:new).with(stdout).and_return(parser)
21
+ }
22
+
23
+ it "should execute --version and parse the result" do
24
+ expect(subject).to eq "the version"
25
+ end
26
+ end
27
+
28
+ context "with path parameter" do
29
+ let(:path) { "/foo/bar" }
30
+
31
+ describe "#initialize" do
32
+ its(:path) { should eq "/foo/bar" }
33
+ end
34
+
35
+ describe "#validate!" do
36
+ subject { instance.validate! }
37
+
38
+ context "with valid path" do
39
+ before {
40
+ expect(File).to receive(:exists?).with("/foo/bar").and_return(true)
41
+ expect(File).to receive(:directory?).with("/foo/bar").and_return(true)
42
+ expect(File).to receive(:exists?).with("/foo/bar/bin/vagrant").and_return(true)
43
+ expect(File).to receive(:executable?).with("/foo/bar/bin/vagrant").and_return(true)
44
+ }
45
+
46
+ it "shouldn't raise any exceptions" do
47
+ expect { subject }.to_not raise_error
48
+ end
49
+
50
+ it "should be chainable" do
51
+ expect(subject).to be_a Derelict::Instance
52
+ end
53
+
54
+ include_context "logged messages"
55
+ let(:expected_logs) {[
56
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
57
+ "DEBUG instance: Starting validation for Derelict::Instance at '/foo/bar'\n",
58
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
59
+ " INFO instance: Successfully validated Derelict::Instance at '/foo/bar'\n",
60
+ ]}
61
+ end
62
+
63
+ context "with non-existent path" do
64
+ before {
65
+ expect(File).to receive(:exists?).with("/foo/bar").and_return(false)
66
+ }
67
+
68
+ it "should raise NotFound" do
69
+ expect { subject }.to raise_error Derelict::Instance::NotFound
70
+ end
71
+
72
+ include_context "logged messages"
73
+ let(:expected_logs) {[
74
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
75
+ "DEBUG instance: Starting validation for Derelict::Instance at '/foo/bar'\n",
76
+ ]}
77
+ end
78
+
79
+ context "with path pointing to a file" do
80
+ before {
81
+ expect(File).to receive(:exists?).with("/foo/bar").and_return(true)
82
+ expect(File).to receive(:directory?).with("/foo/bar").and_return(false)
83
+ }
84
+
85
+ it "should raise NonDirectory" do
86
+ expect { subject }.to raise_error Derelict::Instance::NonDirectory
87
+ end
88
+
89
+ include_context "logged messages"
90
+ let(:expected_logs) {[
91
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
92
+ "DEBUG instance: Starting validation for Derelict::Instance at '/foo/bar'\n",
93
+ ]}
94
+ end
95
+
96
+ context "with vagrant binary missing" do
97
+ before {
98
+ expect(File).to receive(:exists?).with("/foo/bar").and_return(true)
99
+ expect(File).to receive(:directory?).with("/foo/bar").and_return(true)
100
+ expect(File).to receive(:exists?).with("/foo/bar/bin/vagrant").and_return(false)
101
+ }
102
+
103
+ it "should raise MissingBinary" do
104
+ expect { subject }.to raise_error Derelict::Instance::MissingBinary
105
+ end
106
+
107
+ include_context "logged messages"
108
+ let(:expected_logs) {[
109
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
110
+ "DEBUG instance: Starting validation for Derelict::Instance at '/foo/bar'\n",
111
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
112
+ ]}
113
+ end
114
+
115
+ context "with vagrant binary non-executable" do
116
+ before {
117
+ expect(File).to receive(:exists?).with("/foo/bar").and_return(true)
118
+ expect(File).to receive(:directory?).with("/foo/bar").and_return(true)
119
+ expect(File).to receive(:exists?).with("/foo/bar/bin/vagrant").and_return(true)
120
+ expect(File).to receive(:executable?).with("/foo/bar/bin/vagrant").and_return(false)
121
+ }
122
+
123
+ it "should raise MissingBinary" do
124
+ expect { subject }.to raise_error Derelict::Instance::MissingBinary
125
+ end
126
+
127
+ include_context "logged messages"
128
+ let(:expected_logs) {[
129
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
130
+ "DEBUG instance: Starting validation for Derelict::Instance at '/foo/bar'\n",
131
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
132
+ ]}
133
+ end
134
+ end
135
+
136
+ describe "#connect" do
137
+ let(:connection) { double("connection") }
138
+ let(:connection_path) { double("connection_path", :inspect => "connection_path") }
139
+ subject { instance.connect connection_path }
140
+ before do
141
+ con = Derelict::Connection
142
+ args = [instance, connection_path]
143
+ expect(con).to receive(:new).with(*args).and_return(connection)
144
+ expect(connection).to receive(:validate!).and_return(connection)
145
+ end
146
+
147
+ it { should be connection }
148
+
149
+ include_context "logged messages"
150
+ let(:expected_logs) {[
151
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
152
+ " INFO instance: Creating connection for 'connection_path' by Derelict::Instance at '/foo/bar'\n",
153
+ ]}
154
+ end
155
+
156
+ context "with mock Shell" do
157
+ before do
158
+ cmd = "/foo/bar/bin/vagrant test arg\\ 1"
159
+ expect(Shell).to receive(:execute).with(cmd).and_return(result)
160
+ end
161
+
162
+ let(:result) do
163
+ double("result", {
164
+ :stdout => "stdout\n",
165
+ :stderr => "stderr\n",
166
+ :success? => success,
167
+ })
168
+ end
169
+
170
+ let(:success) { double("success") }
171
+
172
+ describe "#execute" do
173
+ subject { instance.execute :test, "arg 1" }
174
+ its(:stdout) { should eq "stdout\n" }
175
+ its(:stderr) { should eq "stderr\n" }
176
+ its(:success?) { should be success }
177
+
178
+ include_context "logged messages"
179
+ let(:expected_logs) {[
180
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
181
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
182
+ "DEBUG instance: Generated command '/foo/bar/bin/vagrant test arg\\ 1' from subcommand 'test' with arguments [\"arg 1\"]\n",
183
+ "DEBUG instance: Executing /foo/bar/bin/vagrant test arg\\ 1 using Derelict::Instance at '/foo/bar'\n",
184
+ ]}
185
+ end
186
+
187
+ describe "#execute!" do
188
+ subject { instance.execute! :test, "arg 1" }
189
+
190
+ context "on success" do
191
+ let(:success) { true }
192
+
193
+ its(:stdout) { should eq "stdout\n" }
194
+ its(:stderr) { should eq "stderr\n" }
195
+ its(:success?) { should be true }
196
+
197
+ include_context "logged messages"
198
+ let(:expected_logs) {[
199
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
200
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
201
+ "DEBUG instance: Generated command '/foo/bar/bin/vagrant test arg\\ 1' from subcommand 'test' with arguments [\"arg 1\"]\n",
202
+ "DEBUG instance: Executing /foo/bar/bin/vagrant test arg\\ 1 using Derelict::Instance at '/foo/bar'\n",
203
+ ]}
204
+ end
205
+
206
+ context "on failure" do
207
+ let(:success) { false }
208
+
209
+ it "should raise CommandFailed" do
210
+ expect { subject }.to raise_error Derelict::Instance::CommandFailed
211
+ end
212
+
213
+ include_context "logged messages"
214
+ let(:expected_logs) {[
215
+ "DEBUG instance: Successfully initialized Derelict::Instance at '/foo/bar'\n",
216
+ "DEBUG instance: Vagrant binary for Derelict::Instance at '/foo/bar' is '/foo/bar/bin/vagrant'\n",
217
+ "DEBUG instance: Generated command '/foo/bar/bin/vagrant test arg\\ 1' from subcommand 'test' with arguments [\"arg 1\"]\n",
218
+ "DEBUG instance: Executing /foo/bar/bin/vagrant test arg\\ 1 using Derelict::Instance at '/foo/bar'\n",
219
+ "DEBUG instance: Generated command '/foo/bar/bin/vagrant test arg\\ 1' from subcommand 'test' with arguments [\"arg 1\"]\n",
220
+ " WARN instance: Command /foo/bar/bin/vagrant test arg\\ 1 failed: Error executing Vagrant command '/foo/bar/bin/vagrant test arg\\ 1'\n",
221
+ ]}
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ describe Derelict::Parser::Status::InvalidFormat do
4
+ it "is autoloaded" do
5
+ should be_a Derelict::Parser::Status::InvalidFormat
6
+ end
7
+
8
+ context "when using default reason" do
9
+ its(:message) { should eq "Output from 'vagrant status' was in an unexpected format" }
10
+ end
11
+
12
+ context "when using custom reason" do
13
+ subject { Derelict::Parser::Status::InvalidFormat.new "reason" }
14
+ its(:message) { should eq "Output from 'vagrant status' was in an unexpected format: reason" }
15
+ end
16
+ end