tenderloin 0.2.0

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