tenderloin 0.2.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 (73) hide show
  1. data/LICENCE +21 -0
  2. data/README.md +50 -0
  3. data/Version +1 -0
  4. data/bin/loin +5 -0
  5. data/config/default.rb +26 -0
  6. data/lib/tenderloin/actions/base.rb +93 -0
  7. data/lib/tenderloin/actions/box/add.rb +22 -0
  8. data/lib/tenderloin/actions/box/destroy.rb +14 -0
  9. data/lib/tenderloin/actions/box/download.rb +63 -0
  10. data/lib/tenderloin/actions/box/unpackage.rb +46 -0
  11. data/lib/tenderloin/actions/runner.rb +138 -0
  12. data/lib/tenderloin/actions/vm/boot.rb +52 -0
  13. data/lib/tenderloin/actions/vm/destroy.rb +18 -0
  14. data/lib/tenderloin/actions/vm/halt.rb +14 -0
  15. data/lib/tenderloin/actions/vm/import.rb +32 -0
  16. data/lib/tenderloin/actions/vm/move_hard_drive.rb +53 -0
  17. data/lib/tenderloin/actions/vm/provision.rb +71 -0
  18. data/lib/tenderloin/actions/vm/reload.rb +17 -0
  19. data/lib/tenderloin/actions/vm/shared_folders.rb +47 -0
  20. data/lib/tenderloin/actions/vm/start.rb +17 -0
  21. data/lib/tenderloin/actions/vm/up.rb +55 -0
  22. data/lib/tenderloin/box.rb +143 -0
  23. data/lib/tenderloin/busy.rb +73 -0
  24. data/lib/tenderloin/cli.rb +59 -0
  25. data/lib/tenderloin/commands.rb +154 -0
  26. data/lib/tenderloin/config.rb +144 -0
  27. data/lib/tenderloin/downloaders/base.rb +13 -0
  28. data/lib/tenderloin/downloaders/file.rb +21 -0
  29. data/lib/tenderloin/downloaders/http.rb +47 -0
  30. data/lib/tenderloin/env.rb +156 -0
  31. data/lib/tenderloin/fusion_vm.rb +85 -0
  32. data/lib/tenderloin/ssh.rb +49 -0
  33. data/lib/tenderloin/util.rb +51 -0
  34. data/lib/tenderloin/vm.rb +63 -0
  35. data/lib/tenderloin/vmx_file.rb +28 -0
  36. data/lib/tenderloin.rb +14 -0
  37. data/script/tenderloin-ssh-expect.sh +23 -0
  38. data/templates/Tenderfile +8 -0
  39. data/test/tenderloin/actions/base_test.rb +32 -0
  40. data/test/tenderloin/actions/box/add_test.rb +37 -0
  41. data/test/tenderloin/actions/box/destroy_test.rb +18 -0
  42. data/test/tenderloin/actions/box/download_test.rb +118 -0
  43. data/test/tenderloin/actions/box/unpackage_test.rb +100 -0
  44. data/test/tenderloin/actions/runner_test.rb +262 -0
  45. data/test/tenderloin/actions/vm/boot_test.rb +55 -0
  46. data/test/tenderloin/actions/vm/destroy_test.rb +24 -0
  47. data/test/tenderloin/actions/vm/down_test.rb +32 -0
  48. data/test/tenderloin/actions/vm/export_test.rb +88 -0
  49. data/test/tenderloin/actions/vm/forward_ports_test.rb +50 -0
  50. data/test/tenderloin/actions/vm/halt_test.rb +27 -0
  51. data/test/tenderloin/actions/vm/import_test.rb +36 -0
  52. data/test/tenderloin/actions/vm/move_hard_drive_test.rb +108 -0
  53. data/test/tenderloin/actions/vm/package_test.rb +181 -0
  54. data/test/tenderloin/actions/vm/provision_test.rb +103 -0
  55. data/test/tenderloin/actions/vm/reload_test.rb +44 -0
  56. data/test/tenderloin/actions/vm/resume_test.rb +27 -0
  57. data/test/tenderloin/actions/vm/shared_folders_test.rb +117 -0
  58. data/test/tenderloin/actions/vm/start_test.rb +28 -0
  59. data/test/tenderloin/actions/vm/suspend_test.rb +27 -0
  60. data/test/tenderloin/actions/vm/up_test.rb +98 -0
  61. data/test/tenderloin/box_test.rb +139 -0
  62. data/test/tenderloin/busy_test.rb +83 -0
  63. data/test/tenderloin/commands_test.rb +269 -0
  64. data/test/tenderloin/config_test.rb +123 -0
  65. data/test/tenderloin/downloaders/base_test.rb +20 -0
  66. data/test/tenderloin/downloaders/file_test.rb +32 -0
  67. data/test/tenderloin/downloaders/http_test.rb +40 -0
  68. data/test/tenderloin/env_test.rb +345 -0
  69. data/test/tenderloin/ssh_test.rb +103 -0
  70. data/test/tenderloin/util_test.rb +64 -0
  71. data/test/tenderloin/vm_test.rb +89 -0
  72. data/test/test_helper.rb +92 -0
  73. metadata +241 -0
@@ -0,0 +1,8 @@
1
+ Tenderloin::Config.run do |config|
2
+ # All Tenderloin configuration is done here. For a detailed explanation
3
+ # and listing of configuration options, please check the documentation
4
+ # online.
5
+
6
+ # Every Tenderloin virtual environment requires a box to build off of.
7
+ config.vm.box = "base"
8
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
2
+
3
+ class BaseActionTest < Test::Unit::TestCase
4
+ should "include the util class so subclasses have access to it" do
5
+ assert Tenderloin::Actions::Base.include?(Tenderloin::Util)
6
+ end
7
+
8
+ context "base instance" do
9
+ setup do
10
+ @mock_vm = mock("vm")
11
+ @base = Tenderloin::Actions::Base.new(@mock_vm)
12
+ end
13
+
14
+ should "allow read-only access to the runner" do
15
+ assert_equal @mock_vm, @base.runner
16
+ end
17
+
18
+ should "implement prepare which does nothing" do
19
+ assert_nothing_raised do
20
+ assert @base.respond_to?(:prepare)
21
+ @base.prepare
22
+ end
23
+ end
24
+
25
+ should "implement the execute! method which does nothing" do
26
+ assert_nothing_raised do
27
+ assert @base.respond_to?(:execute!)
28
+ @base.execute!
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class AddBoxActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @runner, @vm, @action = mock_action(Tenderloin::Actions::Box::Add)
6
+ mock_config
7
+ end
8
+
9
+ context "prepare" do
10
+ setup do
11
+ @default_order = [Tenderloin::Actions::Box::Download, Tenderloin::Actions::Box::Unpackage]
12
+ @runner.stubs(:directory).returns("foo")
13
+ File.stubs(:exists?).returns(false)
14
+ end
15
+
16
+ def setup_action_expectations
17
+ default_seq = sequence("default_seq")
18
+ @default_order.each do |action|
19
+ @runner.expects(:add_action).with(action).once.in_sequence(default_seq)
20
+ end
21
+ end
22
+
23
+ should "setup the proper sequence of actions" do
24
+ setup_action_expectations
25
+ @action.prepare
26
+ end
27
+
28
+ should "result in an action exception if the box already exists" do
29
+ File.expects(:exists?).once.returns(true)
30
+ @runner.expects(:name).twice.returns('foo')
31
+ @runner.expects(:add_action).never
32
+ assert_raise Tenderloin::Actions::ActionException do
33
+ @action.prepare
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class DestroyBoxActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @name = "foo"
6
+ @dir = "foo"
7
+ @runner, @vm, @action = mock_action(Tenderloin::Actions::Box::Destroy)
8
+ @runner.stubs(:directory).returns(@dir)
9
+ mock_config
10
+ end
11
+
12
+ context "executing" do
13
+ should "rm_rf the directory" do
14
+ FileUtils.expects(:rm_rf).with(@dir).once
15
+ @action.execute!
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,118 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class DownloadBoxActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @uri = "foo.com"
6
+ @runner, @vm, @action = mock_action(Tenderloin::Actions::Box::Download)
7
+ @runner.stubs(:uri).returns(@uri)
8
+ @runner.stubs(:temp_path=)
9
+ mock_config
10
+
11
+ Tenderloin::Env.stubs(:tmp_path).returns("foo")
12
+ end
13
+
14
+ context "preparing" do
15
+ setup do
16
+ @uri = mock("uri")
17
+ @uri.stubs(:is_a?).returns(false)
18
+ URI.stubs(:parse).returns(@uri)
19
+ end
20
+
21
+ should "raise an exception if no URI type is matched" do
22
+ @uri.stubs(:is_a?).returns(false)
23
+ assert_raises(Tenderloin::Actions::ActionException) {
24
+ @action.prepare
25
+ }
26
+ end
27
+
28
+ should "set the downloader to file if URI is generic" do
29
+ @uri.stubs(:is_a?).with(URI::Generic).returns(true)
30
+ @action.prepare
31
+ assert @action.downloader.is_a?(Tenderloin::Downloaders::File)
32
+ end
33
+
34
+ should "set the downloader to HTTP if URI is HTTP" do
35
+ @uri.stubs(:is_a?).with(URI::HTTP).returns(true)
36
+ @action.prepare
37
+ assert @action.downloader.is_a?(Tenderloin::Downloaders::HTTP)
38
+ end
39
+ end
40
+
41
+ context "executing" do
42
+ setup do
43
+ @path = "foo"
44
+
45
+ @tempfile = mock("tempfile")
46
+ @tempfile.stubs(:path).returns(@path)
47
+
48
+ @action.stubs(:with_tempfile).yields(@tempfile)
49
+ @action.stubs(:download_to)
50
+ end
51
+
52
+ should "make a tempfile and copy the URI contents to it" do
53
+ @action.expects(:with_tempfile).yields(@tempfile)
54
+ @action.expects(:download_to).with(@tempfile)
55
+ @action.execute!
56
+ end
57
+
58
+ should "save the tempfile path" do
59
+ @runner.expects(:temp_path=).with(@path).once
60
+ @action.execute!
61
+ end
62
+ end
63
+
64
+ context "rescue" do
65
+ should "call cleanup method" do
66
+ @action.expects(:cleanup).once
67
+ @action.rescue(nil)
68
+ end
69
+ end
70
+
71
+ context "tempfile" do
72
+ should "create a tempfile in the tenderloin tmp directory" do
73
+ Tempfile.expects(:open).with(Tenderloin::Actions::Box::Download::BASENAME, Tenderloin::Env.tmp_path).once
74
+ @action.with_tempfile
75
+ end
76
+
77
+ should "yield the tempfile object" do
78
+ @tempfile = mock("tempfile")
79
+ Tempfile.expects(:open).yields(@tempfile)
80
+
81
+ @action.with_tempfile do |otherfile|
82
+ assert @tempfile.equal?(otherfile)
83
+ end
84
+ end
85
+ end
86
+
87
+ context "cleaning up" do
88
+ setup do
89
+ @temp_path = "foo"
90
+ @runner.stubs(:temp_path).returns(@temp_path)
91
+ File.stubs(:exist?).returns(true)
92
+ end
93
+
94
+ should "delete the temporary file if it exists" do
95
+ File.expects(:unlink).with(@temp_path).once
96
+ @action.cleanup
97
+ end
98
+
99
+ should "not delete anything if it doesn't exist" do
100
+ File.stubs(:exist?).returns(false)
101
+ File.expects(:unlink).never
102
+ @action.cleanup
103
+ end
104
+ end
105
+
106
+ context "downloading" do
107
+ setup do
108
+ @downloader = mock("downloader")
109
+ @action.stubs(:downloader).returns(@downloader)
110
+ end
111
+
112
+ should "call download! on the download with the URI and tempfile" do
113
+ tempfile = "foo"
114
+ @downloader.expects(:download!).with(@runner.uri, tempfile)
115
+ @action.download_to(tempfile)
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,100 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class UnpackageBoxActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @runner, @vm, @action = mock_action(Tenderloin::Actions::Box::Unpackage)
6
+ @runner.stubs(:name).returns("foo")
7
+ @runner.stubs(:temp_path).returns("bar")
8
+ mock_config
9
+
10
+ Tenderloin::Env.stubs(:boxes_path).returns("bar")
11
+ end
12
+
13
+ context "executing" do
14
+ setup do
15
+ @runner.stubs(:invoke_around_callback).yields
16
+ end
17
+
18
+ should "execute the proper actions in the proper order" do
19
+ exec_seq = sequence("exec_seq")
20
+ @action.expects(:setup_box_dir).in_sequence(exec_seq)
21
+ @action.expects(:decompress).in_sequence(exec_seq)
22
+ @action.execute!
23
+ end
24
+
25
+ should "execute it in a around block" do
26
+ @runner.expects(:invoke_around_callback).with(:unpackage).once
27
+ @action.execute!
28
+ end
29
+ end
30
+
31
+ context "rescuing" do
32
+ setup do
33
+ File.stubs(:directory?).returns(false)
34
+ FileUtils.stubs(:rm_rf)
35
+
36
+ @box_dir = mock("foo")
37
+ @action.stubs(:box_dir).returns(@box_dir)
38
+ end
39
+
40
+ should "do nothing if a directory doesn't exist" do
41
+ FileUtils.expects(:rm_rf).never
42
+ @action.rescue(nil)
43
+ end
44
+
45
+ should "remove the box directory if it exists" do
46
+ File.expects(:directory?).returns(true)
47
+ FileUtils.expects(:rm_rf).with(@box_dir).once
48
+ @action.rescue(nil)
49
+ end
50
+ end
51
+
52
+ context "box directory" do
53
+ should "return the runner directory" do
54
+ result = mock("object")
55
+ @runner.expects(:directory).once.returns(result)
56
+ assert result.equal?(@action.box_dir)
57
+ end
58
+ end
59
+
60
+ context "setting up the box directory" do
61
+ setup do
62
+ File.stubs(:directory?).returns(false)
63
+ FileUtils.stubs(:mkdir_p)
64
+
65
+ @box_dir = "foo"
66
+ @action.stubs(:box_dir).returns(@box_dir)
67
+ end
68
+
69
+ should "error and exit if the directory exists" do
70
+ File.expects(:directory?).returns(true)
71
+ @action.expects(:error_and_exit).once
72
+ @action.setup_box_dir
73
+ end
74
+
75
+ should "create the directory" do
76
+ FileUtils.expects(:mkdir_p).with(@box_dir).once
77
+ @action.setup_box_dir
78
+ end
79
+ end
80
+
81
+ context "decompressing" do
82
+ setup do
83
+ @box_dir = "foo"
84
+
85
+ @action.stubs(:box_dir).returns(@box_dir)
86
+ Dir.stubs(:chdir).yields
87
+ Archive::Tar::Minitar.stubs(:unpack)
88
+ end
89
+
90
+ should "change to the box directory" do
91
+ Dir.expects(:chdir).with(@box_dir)
92
+ @action.decompress
93
+ end
94
+
95
+ should "open the tar file within the new directory, and extract it all" do
96
+ Archive::Tar::Minitar.expects(:unpack).with(@runner.temp_path, @box_dir).once
97
+ @action.decompress
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,262 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
2
+
3
+ class ActionRunnerTest < Test::Unit::TestCase
4
+ def mock_fake_action(action_klass = nil, runner = nil)
5
+ action = action_klass ? action_klass.new(runner) : mock("action")
6
+ action.stubs(:prepare)
7
+ action.stubs(:execute!)
8
+ action.stubs(:cleanup)
9
+ action
10
+ end
11
+
12
+ context "callbacks" do
13
+ setup do
14
+ @runner = Tenderloin::Actions::Runner.new
15
+ end
16
+
17
+ context "around callbacks" do
18
+ should "invoke before/after_name for around callbacks" do
19
+ block_obj = mock("block_obj")
20
+ around_seq = sequence("around_seq")
21
+ @runner.expects(:invoke_callback).with(:before_foo).once.in_sequence(around_seq)
22
+ block_obj.expects(:foo).once.in_sequence(around_seq)
23
+ @runner.expects(:invoke_callback).with(:after_foo).once.in_sequence(around_seq)
24
+
25
+ @runner.invoke_around_callback(:foo) do
26
+ block_obj.foo
27
+ end
28
+ end
29
+
30
+ should "forward arguments to invoke_callback" do
31
+ @runner.expects(:invoke_callback).with(:before_foo, "foo").once
32
+ @runner.expects(:invoke_callback).with(:after_foo, "foo").once
33
+ @runner.invoke_around_callback(:foo, "foo") do; end
34
+ end
35
+ end
36
+
37
+ should "not invoke callback on actions which don't respond to it" do
38
+ action = mock("action")
39
+ action.stubs(:respond_to?).with(:foo).returns(false)
40
+ action.expects(:foo).never
41
+
42
+ assert_nothing_raised do
43
+ @runner.actions << action
44
+ @runner.invoke_callback(:foo)
45
+ end
46
+ end
47
+
48
+ should "invoke callback on actions which do respond to the method" do
49
+ action = mock("action")
50
+ action.expects(:foo).once
51
+
52
+ @runner.actions << action
53
+ @runner.invoke_callback(:foo)
54
+ end
55
+
56
+ should "collect all the results and return them as an array" do
57
+ result = []
58
+ 3.times do |i|
59
+ action = mock("action#{i}")
60
+ action.expects(:foo).returns("foo#{i}").once
61
+
62
+ @runner.actions << action
63
+ result << "foo#{i}"
64
+ end
65
+
66
+ assert_equal result, @runner.invoke_callback(:foo)
67
+ end
68
+ end
69
+
70
+ context "finding actions" do
71
+ setup do
72
+ @runner = Tenderloin::Actions::Runner.new
73
+ end
74
+
75
+ should "return nil if the action could not be found" do
76
+ assert_nil @runner.find_action(Tenderloin::Actions::VM::Export)
77
+ end
78
+
79
+ should "return the first instance of the action found" do
80
+ @runner.add_action(Tenderloin::Actions::VM::Export)
81
+ @runner.add_action(Tenderloin::Actions::VM::Export)
82
+
83
+ assert @runner.actions[0].equal?(@runner.find_action(Tenderloin::Actions::VM::Export))
84
+ end
85
+ end
86
+
87
+ context "adding actions" do
88
+ setup do
89
+ @runner = Tenderloin::Actions::Runner.new
90
+ end
91
+
92
+ should "initialize the action when added" do
93
+ action_klass = mock("action_class")
94
+ action_inst = mock("action_inst")
95
+ action_klass.expects(:new).once.returns(action_inst)
96
+ @runner.add_action(action_klass)
97
+ assert_equal 1, @runner.actions.length
98
+ end
99
+
100
+ should "initialize the action with given arguments when added" do
101
+ action_klass = mock("action_class")
102
+ action_klass.expects(:new).with(@runner, "foo", "bar").once
103
+ @runner.add_action(action_klass, "foo", "bar")
104
+ end
105
+ end
106
+
107
+ context "class method execute" do
108
+ should "run actions on class method execute!" do
109
+ vm = mock("vm")
110
+ execute_seq = sequence("execute_seq")
111
+ Tenderloin::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
112
+ vm.expects(:add_action).with("foo").in_sequence(execute_seq)
113
+ vm.expects(:execute!).once.in_sequence(execute_seq)
114
+
115
+ Tenderloin::Actions::Runner.execute!("foo")
116
+ end
117
+
118
+ should "forward arguments to add_action on class method execute!" do
119
+ vm = mock("vm")
120
+ execute_seq = sequence("execute_seq")
121
+ Tenderloin::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
122
+ vm.expects(:add_action).with("foo", "bar", "baz").in_sequence(execute_seq)
123
+ vm.expects(:execute!).once.in_sequence(execute_seq)
124
+
125
+ Tenderloin::Actions::Runner.execute!("foo", "bar", "baz")
126
+ end
127
+ end
128
+
129
+ context "instance method execute" do
130
+ setup do
131
+ @runner = Tenderloin::Actions::Runner.new
132
+ @runner.stubs(:action_klasses).returns([Tenderloin::Actions::Base])
133
+ end
134
+
135
+ should "clear the actions and run a single action if given to execute!" do
136
+ action = mock("action")
137
+ run_action = mock("action_run")
138
+ run_class = mock("run_class")
139
+ run_class.expects(:new).once.returns(run_action)
140
+ @runner.actions << action
141
+
142
+ [:prepare, :execute!, :cleanup].each do |method|
143
+ action.expects(method).never
144
+ run_action.expects(method).once
145
+ end
146
+
147
+ @runner.execute!(run_class)
148
+ end
149
+
150
+ should "clear actions after running execute!" do
151
+ @runner.actions << mock_fake_action
152
+ @runner.actions << mock_fake_action
153
+ assert !@runner.actions.empty? # sanity
154
+ @runner.execute!
155
+ assert @runner.actions.empty?
156
+ end
157
+
158
+ should "run #prepare on all actions, then #execute!" do
159
+ action_seq = sequence("action_seq")
160
+ actions = []
161
+ 5.times do |i|
162
+ action = mock("action#{i}")
163
+
164
+ @runner.actions << action
165
+ actions << action
166
+ end
167
+
168
+ [:prepare, :execute!, :cleanup].each do |method|
169
+ actions.each do |action|
170
+ action.expects(method).once.in_sequence(action_seq)
171
+ end
172
+ end
173
+
174
+ @runner.execute!
175
+ end
176
+
177
+ context "exceptions" do
178
+ setup do
179
+ @actions = [mock_fake_action, mock_fake_action]
180
+ @actions.each do |a|
181
+ a.stubs(:rescue)
182
+ @runner.actions << a
183
+ end
184
+
185
+ @exception = Exception.new
186
+ end
187
+
188
+ should "call #rescue on each action if an exception is raised during execute!" do
189
+ @actions.each do |a|
190
+ a.expects(:rescue).with(@exception).once
191
+ end
192
+
193
+ @actions[0].stubs(:execute!).raises(@exception)
194
+
195
+ @runner.expects(:error_and_exit).never
196
+ assert_raises(Exception) { @runner.execute! }
197
+ end
198
+
199
+ should "call #rescue on each action if an exception is raised during prepare" do
200
+ @actions.each do |a|
201
+ a.expects(:rescue).with(@exception).once
202
+ end
203
+
204
+ @actions[0].stubs(:prepare).raises(@exception)
205
+
206
+ @runner.expects(:error_and_exit).never
207
+ assert_raises(Exception) { @runner.execute! }
208
+ end
209
+
210
+ should "call error_and_exit if it is an ActionException" do
211
+ msg = "Message"
212
+ @exception = Tenderloin::Actions::ActionException.new(msg)
213
+ @actions[0].stubs(:prepare).raises(@exception)
214
+
215
+ @runner.expects(:error_and_exit).with(msg).once
216
+ @runner.execute!
217
+ end
218
+ end
219
+ end
220
+
221
+ context "actions" do
222
+ setup do
223
+ @runner = Tenderloin::Actions::Runner.new
224
+ end
225
+
226
+ should "setup actions to be an array" do
227
+ assert_nil @runner.instance_variable_get(:@actions)
228
+ actions = @runner.actions
229
+ assert actions.is_a?(Array)
230
+ assert actions.equal?(@runner.actions)
231
+ end
232
+
233
+ should "be empty initially" do
234
+ assert @runner.actions.empty?
235
+ end
236
+ end
237
+
238
+ context "duplicate action exceptions" do
239
+ setup do
240
+ @runner = Tenderloin::Actions::Runner.new
241
+ end
242
+
243
+ should "should be raised when a duplicate is added" do
244
+ action = mock_fake_action
245
+ 2.times {@runner.actions << action }
246
+ assert_raise Tenderloin::Actions::DuplicateActionException do
247
+ @runner.execute!
248
+ end
249
+ end
250
+
251
+ should "should not be raise when no duplicate actions are present" do
252
+ @runner.actions << mock_fake_action(Tenderloin::Actions::Base, @runner)
253
+ @runner.actions << mock_fake_action(Tenderloin::Actions::VM::Halt, @runner)
254
+
255
+ assert_nothing_raised { @runner.execute! }
256
+ end
257
+
258
+ should "should not raise when a single action is specified" do
259
+ assert_nothing_raised { @runner.execute!(Tenderloin::Actions::Base) }
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class BootActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @mock_vm, @vm, @action = mock_action(Tenderloin::Actions::VM::Boot)
6
+ @mock_vm.stubs(:invoke_callback)
7
+ mock_config
8
+ end
9
+
10
+ context "execution" do
11
+ should "invoke the 'boot' around callback" do
12
+ boot_seq = sequence("boot_seq")
13
+ @mock_vm.expects(:invoke_around_callback).with(:boot).once.in_sequence(boot_seq).yields
14
+ @action.expects(:boot).in_sequence(boot_seq)
15
+ @action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq)
16
+ @action.execute!
17
+ end
18
+
19
+ should "error and exit if the bootup failed" do
20
+ fail_boot_seq = sequence("fail_boot_seq")
21
+ @action.expects(:boot).once.in_sequence(fail_boot_seq)
22
+ @action.expects(:wait_for_boot).returns(false).in_sequence(fail_boot_seq)
23
+ @action.expects(:error_and_exit).once.in_sequence(fail_boot_seq)
24
+ @action.execute!
25
+ end
26
+ end
27
+
28
+ context "booting" do
29
+ should "start the VM in headless mode" do
30
+ @vm.expects(:start).with(:headless, true).once
31
+ @action.boot
32
+ end
33
+ end
34
+
35
+ context "waiting for boot" do
36
+ should "repeatedly ping the SSH port and return false with no response" do
37
+ seq = sequence('pings')
38
+ Tenderloin::SSH.expects(:up?).times(Tenderloin.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq)
39
+ Tenderloin::SSH.expects(:up?).once.returns(true).in_sequence(seq)
40
+ assert @action.wait_for_boot(0)
41
+ end
42
+
43
+ should "ping the max number of times then just return" do
44
+ Tenderloin::SSH.expects(:up?).times(Tenderloin.config[:ssh][:max_tries].to_i).returns(false)
45
+ assert !@action.wait_for_boot(0)
46
+ end
47
+ end
48
+
49
+ context "callbacks" do
50
+ should "setup the root directory shared folder" do
51
+ expected = ["tenderloin-root", Tenderloin::Env.root_path, Tenderloin.config.vm.project_directory]
52
+ assert_equal expected, @action.collect_shared_folders
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class DestroyActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @mock_vm, @vm, @action = mock_action(Tenderloin::Actions::VM::Destroy)
6
+ mock_config
7
+ end
8
+
9
+ context "executing" do
10
+ setup do
11
+ @vm.stubs(:destroy)
12
+ end
13
+
14
+ should "invoke an around callback around the destroy" do
15
+ @mock_vm.expects(:invoke_around_callback).with(:destroy).once
16
+ @action.execute!
17
+ end
18
+
19
+ should "destroy VM and attached images" do
20
+ @vm.expects(:destroy).with(:destroy_image => true).once
21
+ @action.execute!
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
2
+
3
+ class DownActionTest < Test::Unit::TestCase
4
+ setup do
5
+ @mock_vm, @vm, @action = mock_action(Tenderloin::Actions::VM::Down)
6
+ mock_config
7
+ end
8
+
9
+ context "preparing" do
10
+ setup do
11
+ @vm.stubs(:running?).returns(false)
12
+ end
13
+
14
+ def setup_action_expectations(order)
15
+ default_seq = sequence("default_seq")
16
+ order.each do |action|
17
+ @mock_vm.expects(:add_action).with(action).once.in_sequence(default_seq)
18
+ end
19
+ end
20
+
21
+ should "add the destroy action alone if VM is not running" do
22
+ setup_action_expectations([Tenderloin::Actions::VM::Destroy])
23
+ @action.prepare
24
+ end
25
+
26
+ should "add the halt action if the VM is running" do
27
+ @vm.expects(:running?).returns(true)
28
+ setup_action_expectations([Tenderloin::Actions::VM::Halt, Tenderloin::Actions::VM::Destroy])
29
+ @action.prepare
30
+ end
31
+ end
32
+ end