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.
- checksums.yaml +5 -5
- data/README.md +643 -1
- data/bin/dk +7 -0
- data/dk.gemspec +7 -3
- data/lib/dk/ansi.rb +98 -0
- data/lib/dk/cli.rb +173 -0
- data/lib/dk/config.rb +217 -0
- data/lib/dk/config_runner.rb +24 -0
- data/lib/dk/dk_runner.rb +13 -0
- data/lib/dk/dry_runner.rb +43 -0
- data/lib/dk/has_set_param.rb +42 -0
- data/lib/dk/has_ssh_opts.rb +36 -0
- data/lib/dk/has_the_runs.rb +23 -0
- data/lib/dk/has_the_stubs.rb +116 -0
- data/lib/dk/local.rb +84 -0
- data/lib/dk/null_logger.rb +13 -0
- data/lib/dk/remote.rb +132 -0
- data/lib/dk/runner.rb +202 -0
- data/lib/dk/task.rb +266 -0
- data/lib/dk/task_run.rb +17 -0
- data/lib/dk/test_runner.rb +54 -0
- data/lib/dk/tree_runner.rb +64 -0
- data/lib/dk/version.rb +1 -1
- data/lib/dk.rb +23 -1
- data/test/helper.rb +6 -1
- data/test/support/config/dk.rb +7 -0
- data/test/support/config/task_defs.rb +10 -0
- data/test/support/factory.rb +38 -0
- data/test/support/log/.gitkeep +0 -0
- data/test/system/has_the_stubs_tests.rb +355 -0
- data/test/system/runner_tests.rb +222 -0
- data/test/unit/ansi_tests.rb +40 -0
- data/test/unit/cli_tests.rb +317 -0
- data/test/unit/config_runner_tests.rb +60 -0
- data/test/unit/config_tests.rb +427 -0
- data/test/unit/dk_runner_tests.rb +34 -0
- data/test/unit/dk_tests.rb +49 -0
- data/test/unit/dry_runner_tests.rb +71 -0
- data/test/unit/has_set_param_tests.rb +46 -0
- data/test/unit/has_ssh_opts_tests.rb +81 -0
- data/test/unit/has_the_runs_tests.rb +37 -0
- data/test/unit/has_the_stubs_tests.rb +279 -0
- data/test/unit/local_tests.rb +174 -0
- data/test/unit/null_logger_tests.rb +17 -0
- data/test/unit/remote_tests.rb +330 -0
- data/test/unit/runner_tests.rb +398 -0
- data/test/unit/task_run_tests.rb +40 -0
- data/test/unit/task_tests.rb +943 -0
- data/test/unit/test_runner_tests.rb +189 -0
- data/test/unit/tree_runner_tests.rb +152 -0
- 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
|