dk 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 (51) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +643 -1
  3. data/bin/dk +7 -0
  4. data/dk.gemspec +7 -3
  5. data/lib/dk/ansi.rb +98 -0
  6. data/lib/dk/cli.rb +173 -0
  7. data/lib/dk/config.rb +217 -0
  8. data/lib/dk/config_runner.rb +24 -0
  9. data/lib/dk/dk_runner.rb +13 -0
  10. data/lib/dk/dry_runner.rb +43 -0
  11. data/lib/dk/has_set_param.rb +42 -0
  12. data/lib/dk/has_ssh_opts.rb +36 -0
  13. data/lib/dk/has_the_runs.rb +23 -0
  14. data/lib/dk/has_the_stubs.rb +116 -0
  15. data/lib/dk/local.rb +84 -0
  16. data/lib/dk/null_logger.rb +13 -0
  17. data/lib/dk/remote.rb +132 -0
  18. data/lib/dk/runner.rb +202 -0
  19. data/lib/dk/task.rb +266 -0
  20. data/lib/dk/task_run.rb +17 -0
  21. data/lib/dk/test_runner.rb +54 -0
  22. data/lib/dk/tree_runner.rb +64 -0
  23. data/lib/dk/version.rb +1 -1
  24. data/lib/dk.rb +23 -1
  25. data/test/helper.rb +6 -1
  26. data/test/support/config/dk.rb +7 -0
  27. data/test/support/config/task_defs.rb +10 -0
  28. data/test/support/factory.rb +38 -0
  29. data/test/support/log/.gitkeep +0 -0
  30. data/test/system/has_the_stubs_tests.rb +355 -0
  31. data/test/system/runner_tests.rb +222 -0
  32. data/test/unit/ansi_tests.rb +40 -0
  33. data/test/unit/cli_tests.rb +317 -0
  34. data/test/unit/config_runner_tests.rb +60 -0
  35. data/test/unit/config_tests.rb +427 -0
  36. data/test/unit/dk_runner_tests.rb +34 -0
  37. data/test/unit/dk_tests.rb +49 -0
  38. data/test/unit/dry_runner_tests.rb +71 -0
  39. data/test/unit/has_set_param_tests.rb +46 -0
  40. data/test/unit/has_ssh_opts_tests.rb +81 -0
  41. data/test/unit/has_the_runs_tests.rb +37 -0
  42. data/test/unit/has_the_stubs_tests.rb +279 -0
  43. data/test/unit/local_tests.rb +174 -0
  44. data/test/unit/null_logger_tests.rb +17 -0
  45. data/test/unit/remote_tests.rb +330 -0
  46. data/test/unit/runner_tests.rb +398 -0
  47. data/test/unit/task_run_tests.rb +40 -0
  48. data/test/unit/task_tests.rb +943 -0
  49. data/test/unit/test_runner_tests.rb +189 -0
  50. data/test/unit/tree_runner_tests.rb +152 -0
  51. metadata +106 -9
@@ -0,0 +1,398 @@
1
+ require 'assert'
2
+ require 'dk/runner'
3
+
4
+ require 'dk'
5
+ require 'dk/ansi'
6
+ require 'dk/config'
7
+ require 'dk/has_set_param'
8
+ require 'dk/has_ssh_opts'
9
+ require 'dk/local'
10
+ require 'dk/null_logger'
11
+ require 'dk/remote'
12
+ require 'dk/task'
13
+
14
+ class Dk::Runner
15
+
16
+ class UnitTests < Assert::Context
17
+ desc "Dk::Runner"
18
+ setup do
19
+ @runner_class = Dk::Runner
20
+ end
21
+ subject{ @runner_class }
22
+
23
+ should "include HasSetParam" do
24
+ assert_includes Dk::HasSetParam, subject
25
+ end
26
+
27
+ should "include HasSSHOpts" do
28
+ assert_includes Dk::HasSSHOpts, subject
29
+ end
30
+
31
+ should "know its log prefix values" do
32
+ assert_equal ' >>> ', subject::TASK_START_LOG_PREFIX
33
+ assert_equal ' <<< ', subject::TASK_END_LOG_PREFIX
34
+ assert_equal ' ', subject::INDENT_LOG_PREFIX
35
+ assert_equal '[CMD] ', subject::CMD_LOG_PREFIX
36
+ assert_equal '[SSH] ', subject::SSH_LOG_PREFIX
37
+ assert_equal "> ", subject::CMD_SSH_OUT_LOG_PREFIX
38
+ end
39
+
40
+ end
41
+
42
+ class InitTests < UnitTests
43
+ desc "when init"
44
+ setup do
45
+ @args = {
46
+ :params => { Factory.string => Factory.string },
47
+ :logger => Dk::NullLogger.new
48
+ }
49
+ @runner = @runner_class.new(@args)
50
+ end
51
+ subject{ @runner }
52
+
53
+ should have_readers :params, :logger
54
+ should have_imeths :task_callbacks, :task_callback_task_classes
55
+ should have_imeths :add_task_callback
56
+ should have_imeths :run, :run_task
57
+ should have_imeths :log_info, :log_debug, :log_error
58
+ should have_imeths :log_task_run, :log_cli_run
59
+ should have_imeths :cmd, :ssh
60
+ should have_imeths :has_run_task?, :pretty_run_time
61
+
62
+ should "know its attrs" do
63
+ assert_equal @args[:params], subject.params
64
+ assert_equal @args[:logger], subject.logger
65
+ end
66
+
67
+ should "default its attrs" do
68
+ runner = @runner_class.new
69
+
70
+ assert_equal Hash.new, runner.params
71
+
72
+ assert_equal [], runner.task_callbacks('before', Factory.string)
73
+ assert_equal [], runner.task_callbacks('prepend_before', Factory.string)
74
+ assert_equal [], runner.task_callbacks('after', Factory.string)
75
+ assert_equal [], runner.task_callbacks('prepend_after', Factory.string)
76
+
77
+ assert_equal Dk::Config::DEFAULT_SSH_HOSTS, runner.ssh_hosts
78
+ assert_equal Dk::Config::DEFAULT_SSH_ARGS, runner.ssh_args
79
+ assert_equal Dk::Config::DEFAULT_HOST_SSH_ARGS, runner.host_ssh_args
80
+
81
+ assert_instance_of Dk::NullLogger, @runner_class.new.logger
82
+ end
83
+
84
+ should "use params that complain when accessing missing keys" do
85
+ key = Factory.string
86
+ assert_raises(Dk::NoParamError){ subject.params[key] }
87
+
88
+ subject.params[key] = Factory.string
89
+ assert_nothing_raised{ subject.params[key] }
90
+ end
91
+
92
+ should "stringify the params passed to it" do
93
+ key, value = Factory.string.to_sym, Factory.string
94
+ params = { key => [{ key => value }] }
95
+ runner = @runner_class.new(:params => params)
96
+
97
+ exp = { key.to_s => [{ key.to_s => value }] }
98
+ assert_equal exp, runner.params
99
+ end
100
+
101
+ should "lookup any given task callbacks by name and task class" do
102
+ name = ['before', 'prepend_before', 'after', 'prepend_after'].sample
103
+
104
+ task_class = Factory.string
105
+ callbacks = Factory.integer(3).times.map{ Dk::Task::Callback.new(Factory.string) }
106
+ runner = @runner_class.new("#{name}_callbacks".to_sym => { task_class => callbacks })
107
+
108
+ assert_equal callbacks, runner.task_callbacks(name, task_class)
109
+
110
+ exp = callbacks.map(&:task_class)
111
+ assert_equal exp, runner.task_callback_task_classes(name, task_class)
112
+ end
113
+
114
+ should "add task callbacks by name and task class" do
115
+ name = ['before', 'prepend_before', 'after', 'prepend_after'].sample
116
+
117
+ subject = Factory.string
118
+ callback = Factory.string
119
+ callback_params = { Factory.string => Factory.string }
120
+
121
+ runner = @runner_class.new
122
+ runner.add_task_callback(name, subject, callback, callback_params)
123
+
124
+ exp = [Dk::Task::Callback.new(callback, callback_params)]
125
+ assert_equal exp, runner.task_callbacks(name, subject)
126
+ assert_equal [callback], runner.task_callback_task_classes(name, subject)
127
+ end
128
+
129
+ should "build and run a given task class, honoring any run only once setting" do
130
+ params = { Factory.string => Factory.string }
131
+
132
+ task = subject.run(TestTask)
133
+ assert_true task.run_called
134
+ assert_equal Hash.new, task.run_params
135
+
136
+ task = subject.run(TestTask, params)
137
+ assert_true task.run_called
138
+ assert_equal params, task.run_params
139
+
140
+ task = subject.run_task(TestTask)
141
+ assert_true task.run_called
142
+ assert_equal Hash.new, task.run_params
143
+
144
+ task = subject.run_task(TestTask, params)
145
+ assert_true task.run_called
146
+ assert_equal params, task.run_params
147
+
148
+ TestTask.run_only_once(true)
149
+
150
+ task = subject.run(TestTask)
151
+ assert_nil task.run_called
152
+ assert_nil task.run_params
153
+
154
+ task = subject.run(TestTask, params)
155
+ assert_nil task.run_called
156
+ assert_nil task.run_params
157
+
158
+ task = subject.run_task(TestTask)
159
+ assert_nil task.run_called
160
+ assert_nil task.run_params
161
+
162
+ task = subject.run_task(TestTask, params)
163
+ assert_nil task.run_called
164
+ assert_nil task.run_params
165
+ end
166
+
167
+ should "call to its logger for its log_{info|debug|error} methods" do
168
+ logger_info_called_with = nil
169
+ Assert.stub(@args[:logger], :info){ |*args| logger_info_called_with = args }
170
+
171
+ logger_debug_called_with = nil
172
+ Assert.stub(@args[:logger], :debug){ |*args| logger_debug_called_with = args }
173
+
174
+ logger_error_called_with = nil
175
+ Assert.stub(@args[:logger], :error){ |*args| logger_error_called_with = args }
176
+
177
+ msg = Factory.string
178
+ styles = [[], [:bold, :red]].sample
179
+
180
+ subject.log_info msg, *styles
181
+ exp = ["#{INDENT_LOG_PREFIX}#{Dk::Ansi.styled_msg(msg, *styles)}"]
182
+ assert_equal exp, logger_info_called_with
183
+
184
+ subject.log_debug msg, *styles
185
+ exp = ["#{INDENT_LOG_PREFIX}#{Dk::Ansi.styled_msg(msg, *styles)}"]
186
+ assert_equal exp, logger_debug_called_with
187
+
188
+ subject.log_error msg, *styles
189
+ exp = ["#{INDENT_LOG_PREFIX}#{Dk::Ansi.styled_msg(msg, *styles)}"]
190
+ assert_equal exp, logger_error_called_with
191
+ end
192
+
193
+ should "debug log the start/finish of task runs, including their run time" do
194
+ logger_debug_calls = []
195
+ Assert.stub(@args[:logger], :debug){ |*args| logger_debug_calls << args }
196
+
197
+ pretty_run_time = Factory.string
198
+ Assert.stub(subject, :pretty_run_time){ pretty_run_time }
199
+
200
+ task_class = Class.new{ include Dk::Task; def run!; end }
201
+ subject.log_task_run(task_class){}
202
+
203
+ exp = [
204
+ ["#{TASK_START_LOG_PREFIX}#{task_class}"],
205
+ ["#{TASK_END_LOG_PREFIX}#{task_class} (#{pretty_run_time})"],
206
+ ]
207
+ assert_equal exp, logger_debug_calls
208
+ end
209
+
210
+ should "log the start/finish of CLI task runs, including their run time" do
211
+ logger_info_calls = []
212
+ Assert.stub(@args[:logger], :info){ |*args| logger_info_calls << args }
213
+
214
+ pretty_run_time = Factory.string
215
+ Assert.stub(subject, :pretty_run_time){ pretty_run_time }
216
+
217
+ task_name = Factory.string
218
+ subject.log_cli_task_run(task_name){}
219
+
220
+ exp = [
221
+ ["Starting `#{task_name}`."],
222
+ ["`#{task_name}` finished in #{pretty_run_time}."],
223
+ [""],
224
+ [""]
225
+ ]
226
+ assert_equal exp, logger_info_calls
227
+ end
228
+
229
+ should "log the start of CLI runs" do
230
+ logger_calls = []
231
+ Assert.stub(@args[:logger], :debug){ |*args| logger_calls << [:debug, *args] }
232
+ Assert.stub(@args[:logger], :info){ |*args| logger_calls << [:info, *args] }
233
+
234
+ pretty_run_time = Factory.string
235
+ Assert.stub(subject, :pretty_run_time){ pretty_run_time }
236
+
237
+ cli_argv = Factory.string
238
+ subject.log_cli_run(cli_argv){}
239
+
240
+ exp = 15.times.map{ [:debug, ""] } + [
241
+ [:debug, "===================================="],
242
+ [:debug, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> `#{cli_argv}`"],
243
+ [:debug, "===================================="],
244
+ [:info, "(#{pretty_run_time})"],
245
+ [:debug, "===================================="],
246
+ [:debug, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< `#{cli_argv}`"],
247
+ [:debug, "===================================="]
248
+ ]
249
+ assert_equal exp, logger_calls
250
+ end
251
+
252
+ should "know if it has run a task or not" do
253
+ assert_false subject.has_run_task?(TestTask)
254
+ subject.run(TestTask)
255
+ assert_true subject.has_run_task?(TestTask)
256
+
257
+ task_class = Class.new{ include Dk::Task; def run!; end }
258
+ assert_false subject.has_run_task?(task_class)
259
+ subject.run_task(task_class)
260
+ assert_true subject.has_run_task?(task_class)
261
+ end
262
+
263
+ should "know how to format raw run times and make them 'pretty'" do
264
+ run_time = Factory.float(1.5)
265
+ exp = "#{(run_time * 10_000).round / 10.0}ms"
266
+ assert_equal exp, subject.pretty_run_time(run_time)
267
+
268
+ run_time = Factory.float (0.1) + 1.5
269
+ exp = "#{run_time.to_i / 60}:#{(run_time.round % 60).to_i.to_s.rjust(2, '0')}s"
270
+ assert_equal exp, subject.pretty_run_time(run_time)
271
+ end
272
+
273
+ end
274
+
275
+ class CmdSetupTests < UnitTests
276
+ setup do
277
+ @cmd_str = Factory.string
278
+ @cmd_input = Factory.string
279
+ @cmd_given_opts = { Factory.string => Factory.string }
280
+
281
+ @log_out = ""
282
+ logger = Logger.new(StringIO.new(@log_out))
283
+ logger.formatter = proc do |severity, datetime, progname, msg|
284
+ "#{severity} -- #{msg}\n"
285
+ end
286
+ @runner_opts = { :logger => logger }
287
+ end
288
+ subject{ @runner }
289
+
290
+ end
291
+
292
+ class CmdTests < CmdSetupTests
293
+ desc "running cmds"
294
+ setup do
295
+ @local_cmd = nil
296
+ @local_cmd_new_called_with = nil
297
+ Assert.stub(Dk::Local::Cmd, :new) do |*args|
298
+ @local_cmd_new_called_with = args
299
+ @local_cmd = Dk::Local::CmdSpy.new(*args).tap do |cmd_spy|
300
+ cmd_spy.stdout = Factory.stdout
301
+ end
302
+ end
303
+
304
+ @task = Factory.string
305
+ @runner = @runner_class.new(@runner_opts)
306
+
307
+ @pretty_run_time = Factory.string
308
+ Assert.stub(subject, :pretty_run_time){ @pretty_run_time }
309
+ end
310
+
311
+ should "build, log and run local cmds" do
312
+ @runner.cmd(@task, @cmd_str, @cmd_input, @cmd_given_opts)
313
+
314
+ exp = [@cmd_str, @cmd_given_opts]
315
+ assert_equal exp, @local_cmd_new_called_with
316
+
317
+ assert_not_nil @local_cmd
318
+ assert_true @local_cmd.run_called?
319
+ assert_equal @cmd_input, @local_cmd.run_input
320
+
321
+ assert_equal exp_log_output(@local_cmd), @log_out
322
+ end
323
+
324
+ private
325
+
326
+ def exp_log_output(cmd)
327
+ ( ["INFO -- #{CMD_LOG_PREFIX}#{cmd.cmd_str}\n"] +
328
+ ["INFO -- #{INDENT_LOG_PREFIX}(#{@pretty_run_time})\n"] +
329
+ cmd.output_lines.map do |ol|
330
+ "DEBUG -- #{INDENT_LOG_PREFIX}#{CMD_SSH_OUT_LOG_PREFIX}#{ol.line}\n"
331
+ end
332
+ ).join("")
333
+ end
334
+
335
+ end
336
+
337
+ class SSHCmdTests < CmdSetupTests
338
+ desc "running ssh cmds"
339
+ setup do
340
+ @cmd_ssh_opts = { :hosts => Factory.hosts }
341
+
342
+ @remote_cmd = nil
343
+ @remote_cmd_new_called_with = nil
344
+ Assert.stub(Dk::Remote::Cmd, :new) do |*args|
345
+ @remote_cmd_new_called_with = args
346
+ @remote_cmd = Dk::Remote::CmdSpy.new(*args).tap do |cmd_spy|
347
+ cmd_spy.stdout = Factory.stdout
348
+ end
349
+ end
350
+
351
+ @task = Factory.string
352
+ @runner = @runner_class.new(@runner_opts)
353
+
354
+ @pretty_run_time = Factory.string
355
+ Assert.stub(subject, :pretty_run_time){ @pretty_run_time }
356
+ end
357
+
358
+ should "build, log and run remote cmds" do
359
+ @runner.ssh(@task, @cmd_str, @cmd_input, @cmd_given_opts, @cmd_ssh_opts)
360
+
361
+ exp = [@cmd_str, @cmd_ssh_opts]
362
+ assert_equal exp, @remote_cmd_new_called_with
363
+
364
+ assert_not_nil @remote_cmd
365
+ assert_true @remote_cmd.run_called?
366
+ assert_equal @cmd_input, @remote_cmd.run_input
367
+
368
+ assert_equal exp_log_output(@remote_cmd), @log_out
369
+ end
370
+
371
+ private
372
+
373
+ def exp_log_output(cmd)
374
+ ( ["INFO -- #{SSH_LOG_PREFIX}#{cmd.cmd_str}\n"] +
375
+ ["DEBUG -- #{INDENT_LOG_PREFIX}#{cmd.ssh_cmd_str('<host>')}\n"] +
376
+ cmd.hosts.map{ |h| "INFO -- #{INDENT_LOG_PREFIX}[#{h}]\n" } +
377
+ ["INFO -- #{INDENT_LOG_PREFIX}(#{@pretty_run_time})\n"] +
378
+ cmd.output_lines.map do |ol|
379
+ "DEBUG -- #{INDENT_LOG_PREFIX}[#{ol.host}] #{CMD_SSH_OUT_LOG_PREFIX}#{ol.line}\n"
380
+ end
381
+ ).join("")
382
+ end
383
+
384
+ end
385
+
386
+ class TestTask
387
+ include Dk::Task
388
+
389
+ attr_reader :run_called, :run_params
390
+
391
+ def run!
392
+ @run_called = true
393
+ @run_params = params
394
+ end
395
+
396
+ end
397
+
398
+ end
@@ -0,0 +1,40 @@
1
+ require 'assert'
2
+ require 'dk/task_run'
3
+
4
+ require 'dk/has_the_runs'
5
+
6
+ class Dk::TaskRun
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "Dk::TaskRun"
10
+ setup do
11
+ @task_run_class = Dk::TaskRun
12
+ end
13
+ subject{ @task_run_class }
14
+
15
+ should "have the runs" do
16
+ assert_includes Dk::HasTheRuns, subject
17
+ end
18
+
19
+ end
20
+
21
+ class InitTests < UnitTests
22
+ desc "when init"
23
+ setup do
24
+ @task_class = Factory.string
25
+ @params = { Factory.string => Factory.string }
26
+
27
+ @task_run = @task_run_class.new(@task_class, @params)
28
+ end
29
+ subject{ @task_run }
30
+
31
+ should have_imeths :task_class, :params
32
+
33
+ should "know its task class and params" do
34
+ assert_equal @task_class, subject.task_class
35
+ assert_equal @params, subject.params
36
+ end
37
+
38
+ end
39
+
40
+ end