derelict 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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