singularity_dsl 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rubocop.yml +10 -0
- data/.singularityrc +12 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +52 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +24 -0
- data/bin/singularity_runner +5 -0
- data/lib/singularity_dsl/application.rb +76 -0
- data/lib/singularity_dsl/cli/cli.rb +125 -0
- data/lib/singularity_dsl/cli/table.rb +32 -0
- data/lib/singularity_dsl/dsl/batch.rb +23 -0
- data/lib/singularity_dsl/dsl/changeset.rb +39 -0
- data/lib/singularity_dsl/dsl/components.rb +7 -0
- data/lib/singularity_dsl/dsl/dsl.rb +71 -0
- data/lib/singularity_dsl/dsl/event_store.rb +34 -0
- data/lib/singularity_dsl/dsl/registry.rb +60 -0
- data/lib/singularity_dsl/dsl/runner.rb +67 -0
- data/lib/singularity_dsl/dsl/utils.rb +28 -0
- data/lib/singularity_dsl/errors.rb +35 -0
- data/lib/singularity_dsl/files.rb +20 -0
- data/lib/singularity_dsl/git_helper.rb +94 -0
- data/lib/singularity_dsl/runstate.rb +30 -0
- data/lib/singularity_dsl/stdout.rb +16 -0
- data/lib/singularity_dsl/task.rb +30 -0
- data/lib/singularity_dsl/tasks/rake.rb +31 -0
- data/lib/singularity_dsl/tasks/rspec.rb +32 -0
- data/lib/singularity_dsl/tasks/rubocop.rb +54 -0
- data/lib/singularity_dsl/tasks/shell_task.rb +90 -0
- data/lib/singularity_dsl/version.rb +6 -0
- data/lib/singularity_dsl.rb +9 -0
- data/singularity_dsl.gemspec +31 -0
- data/spec/singularity_dsl/application_spec.rb +92 -0
- data/spec/singularity_dsl/dsl/batch_spec.rb +30 -0
- data/spec/singularity_dsl/dsl/changeset_spec.rb +54 -0
- data/spec/singularity_dsl/dsl/dsl_spec.rb +45 -0
- data/spec/singularity_dsl/dsl/event_store_spec.rb +44 -0
- data/spec/singularity_dsl/dsl/registry_spec.rb +39 -0
- data/spec/singularity_dsl/dsl/runner_spec.rb +39 -0
- data/spec/singularity_dsl/dsl/stubs/tasks/dummy_task.rb +4 -0
- data/spec/singularity_dsl/dsl/utils_spec.rb +33 -0
- data/spec/singularity_dsl/git_helper_spec.rb +72 -0
- data/spec/singularity_dsl/runstate_spec.rb +73 -0
- data/spec/singularity_dsl/task_spec.rb +54 -0
- data/spec/singularity_dsl/tasks/shell_task_spec.rb +119 -0
- metadata +231 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'singularity_dsl/dsl/batch'
|
4
|
+
require 'singularity_dsl/dsl/dsl'
|
5
|
+
require 'singularity_dsl/errors'
|
6
|
+
require 'singularity_dsl/runstate'
|
7
|
+
|
8
|
+
module SingularityDsl
|
9
|
+
# DSL classes & fxs
|
10
|
+
module Dsl
|
11
|
+
# class that runs Singularity::Dsl
|
12
|
+
class Runner
|
13
|
+
include SingularityDsl::Errors
|
14
|
+
|
15
|
+
attr_reader :state, :dsl
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@dsl = Dsl.new
|
19
|
+
@state = Runstate.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(batch = false, pass_errors = false)
|
23
|
+
@dsl.registry.run_list(batch).each do |task|
|
24
|
+
task.execute.tap do |status|
|
25
|
+
failed = task.failed_status status
|
26
|
+
record_failure task if failed
|
27
|
+
resource_fail task if failed && !pass_errors
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_ex_script(path)
|
33
|
+
@dsl.instance_eval(::File.read path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def post_actions
|
37
|
+
@dsl.error_proc.call if @state.error
|
38
|
+
@dsl.fail_proc.call if @state.failed
|
39
|
+
@dsl.success_proc.call unless @state.failed || @state.error
|
40
|
+
@dsl.always_proc.call
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def record_failure(task)
|
46
|
+
failure = klass_failed(task)
|
47
|
+
failure += " #{task.task_name}" if task.task_name
|
48
|
+
@state.add_failure failure
|
49
|
+
end
|
50
|
+
|
51
|
+
def raise_dsl_set_err(dsl)
|
52
|
+
fail "Invalid object given #{dsl}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def execute_task(task)
|
56
|
+
failed = false
|
57
|
+
begin
|
58
|
+
failed = task.execute
|
59
|
+
rescue ::StandardError => err
|
60
|
+
@state.add_error "#{err.message}\n#{err.backtrace}"
|
61
|
+
resource_err task
|
62
|
+
end
|
63
|
+
failed
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SingularityDsl
|
4
|
+
# DSL classes & fxs
|
5
|
+
module Dsl
|
6
|
+
# Utility functions mixin module
|
7
|
+
module Utils
|
8
|
+
def task_name(klass)
|
9
|
+
klass.to_s.split(':').last
|
10
|
+
end
|
11
|
+
|
12
|
+
def task(klass)
|
13
|
+
task_name(klass).downcase.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
def task_list
|
17
|
+
klasses = []
|
18
|
+
SingularityDsl.constants.each do |klass|
|
19
|
+
klass = SingularityDsl.const_get(klass)
|
20
|
+
next unless klass.is_a? Class
|
21
|
+
next unless klass < Task
|
22
|
+
klasses.push klass
|
23
|
+
end
|
24
|
+
klasses
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SingularityDsl
|
4
|
+
# error & failure classes / methods
|
5
|
+
module Errors
|
6
|
+
class ResourceFail < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class ResourceError < RuntimeError
|
10
|
+
end
|
11
|
+
|
12
|
+
def klass_name(obj)
|
13
|
+
return obj.class if obj.class < Object
|
14
|
+
obj
|
15
|
+
end
|
16
|
+
|
17
|
+
def klass_error(klass)
|
18
|
+
klass = klass_name klass
|
19
|
+
"#{klass} threw an exception while executing"
|
20
|
+
end
|
21
|
+
|
22
|
+
def klass_failed(klass)
|
23
|
+
klass = klass_name klass
|
24
|
+
"#{klass} failed."
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_fail(klass)
|
28
|
+
fail ResourceFail, klass_failed(klass)
|
29
|
+
end
|
30
|
+
|
31
|
+
def resource_err(klass)
|
32
|
+
fail ResourceError, klass_error(klass)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SingularityDsl
|
4
|
+
# File helper fx mixin
|
5
|
+
module Files
|
6
|
+
private
|
7
|
+
|
8
|
+
def files_in_path(path)
|
9
|
+
paths = [path] if ::File.file? path
|
10
|
+
paths = dir_glob path if ::File.directory? path
|
11
|
+
paths ||= []
|
12
|
+
paths
|
13
|
+
end
|
14
|
+
|
15
|
+
def dir_glob(dir)
|
16
|
+
dir = ::File.join dir, '**'
|
17
|
+
::Dir.glob dir
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'mixlib/shellout'
|
4
|
+
|
5
|
+
module SingularityDsl
|
6
|
+
# wrapper class for rugged
|
7
|
+
class GitHelper
|
8
|
+
attr_reader :dir
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
throw 'git not installed' unless git_installed
|
12
|
+
end
|
13
|
+
|
14
|
+
def clean_reset
|
15
|
+
fail 'failed to clean' unless (reset | clean) == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def checkout_remote(branch, remote)
|
19
|
+
remote_action branch, remote, 'checkout'
|
20
|
+
end
|
21
|
+
|
22
|
+
def merge_remote(branch, url)
|
23
|
+
remote_action branch, url, 'merge'
|
24
|
+
end
|
25
|
+
|
26
|
+
def diff_remote(branch, url, flags = '')
|
27
|
+
flags = flags.join ' ' if flags.kind_of? Array
|
28
|
+
cmd = remote_cmd branch, url, "diff #{flags}"
|
29
|
+
task = Mixlib::ShellOut.new cmd
|
30
|
+
task.run_command
|
31
|
+
task.stdout
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_remote(url)
|
35
|
+
remote = remote_from_url url
|
36
|
+
exec("git remote add #{remote} #{url}")
|
37
|
+
fetch_all
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_remote(url)
|
41
|
+
remote = remote_from_url url
|
42
|
+
return 0 if remote.eql? 'origin'
|
43
|
+
exec("git remote rm #{remote}")
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def remote_cmd(branch, url, action)
|
49
|
+
remote = remote_from_url url
|
50
|
+
"git #{action} #{remote}/#{branch}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def remote_action(branch, url, action)
|
54
|
+
status = exec(remote_cmd branch, url, action)
|
55
|
+
fail "failed to #{action}" unless status == 0
|
56
|
+
status
|
57
|
+
end
|
58
|
+
|
59
|
+
def remote_from_url(url)
|
60
|
+
return 'origin' if url.nil? || !url
|
61
|
+
url.split(':').last.gsub('/', '_')
|
62
|
+
end
|
63
|
+
|
64
|
+
def fetch_all
|
65
|
+
exec 'git fetch --all'
|
66
|
+
end
|
67
|
+
|
68
|
+
def remotes
|
69
|
+
(`git remote`.split "\n") - ['origin']
|
70
|
+
end
|
71
|
+
|
72
|
+
def index_path
|
73
|
+
::File.join(@repo.path, 'index')
|
74
|
+
end
|
75
|
+
|
76
|
+
def git_installed
|
77
|
+
!`which git`.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
def reset
|
81
|
+
exec 'git add . && git reset --hard'
|
82
|
+
end
|
83
|
+
|
84
|
+
def clean
|
85
|
+
exec 'git clean -fdx'
|
86
|
+
end
|
87
|
+
|
88
|
+
def exec(cmd)
|
89
|
+
task = Mixlib::ShellOut.new cmd
|
90
|
+
task.run_command
|
91
|
+
task.exitstatus
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SingularityDsl
|
4
|
+
# abstraction class for the overall runtime state
|
5
|
+
class Runstate
|
6
|
+
attr_reader :errors, :failures, :error, :failed
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@error = false
|
10
|
+
@errors = []
|
11
|
+
@failed = false
|
12
|
+
@failures = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_failure(fail_msg)
|
16
|
+
@failed = true
|
17
|
+
@failures.push fail_msg
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_error(err_msg)
|
21
|
+
@error = true
|
22
|
+
@errors.push err_msg
|
23
|
+
end
|
24
|
+
|
25
|
+
def exit_code
|
26
|
+
return 1 if @error || @failed
|
27
|
+
0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module SingularityDsl
|
4
|
+
# Task abstraction class
|
5
|
+
class Task
|
6
|
+
def initialize(&block)
|
7
|
+
instance_eval(&block) unless block.nil?
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_file(file)
|
11
|
+
throw "Cannot find #{file}" unless File.exist? file
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
fail 'SingularityDsl::Task::execute not implemented'
|
16
|
+
end
|
17
|
+
|
18
|
+
def failed_status(status)
|
19
|
+
![nil, 0, false].include? status
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
"Runs #{self.class} task"
|
24
|
+
end
|
25
|
+
|
26
|
+
def task_name
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
# Rake Task
|
6
|
+
class Rake < Task
|
7
|
+
attr_accessor :target, :rake
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
::Rake.application.init
|
11
|
+
@rake = ::Rake.application
|
12
|
+
super(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def target(target)
|
16
|
+
@target = target
|
17
|
+
@target.strip!
|
18
|
+
end
|
19
|
+
|
20
|
+
def execute
|
21
|
+
throw 'target is required' if @target.nil?
|
22
|
+
@rake.load_rakefile
|
23
|
+
ret = @rake[@target].invoke
|
24
|
+
return ret.count if ret.kind_of? Array
|
25
|
+
ret
|
26
|
+
end
|
27
|
+
|
28
|
+
def description
|
29
|
+
'Simple resource to just wrap the Rake CLI'
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
# RSpec Task
|
6
|
+
class RSpec < Task
|
7
|
+
attr_accessor :spec_dir, :config_file
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
@spec_dir ||= './spec'
|
11
|
+
@config_file ||= './.rspec'
|
12
|
+
super(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def config_file(file)
|
16
|
+
validate_file file
|
17
|
+
@config_file = file
|
18
|
+
end
|
19
|
+
|
20
|
+
def spec_dir(dir)
|
21
|
+
validate_file dir
|
22
|
+
@spec_dir = dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
::RSpec::Core::Runner.run([@spec_dir])
|
27
|
+
end
|
28
|
+
|
29
|
+
def description
|
30
|
+
'Run RSpec tests. Uses RSpec::Core'
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubocop'
|
4
|
+
|
5
|
+
# Rubocop task
|
6
|
+
# Intentionally NOT a rake task - for some reason the syck YAML parser
|
7
|
+
# that Rubocop uses internally freaks out when a
|
8
|
+
# ::Rake::Application[:task].invoke is called from a task
|
9
|
+
class Rubocop < Task
|
10
|
+
# :files => specific files to run against
|
11
|
+
# :cfg_file => separate config file
|
12
|
+
def initialize(&block)
|
13
|
+
@default_config = './.rubocop.yml'
|
14
|
+
@files = []
|
15
|
+
@cfg_files = [@default_config]
|
16
|
+
@cfg_store = ::RuboCop::ConfigStore.new
|
17
|
+
super(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def config_file(file)
|
21
|
+
validate_file file
|
22
|
+
|
23
|
+
return if @cfg_files.include? file
|
24
|
+
warn 'Loading multiple configs' if File.exist? @default_config
|
25
|
+
|
26
|
+
@cfg_files.push file
|
27
|
+
|
28
|
+
# this does a merge of options...
|
29
|
+
@cfg_store.options_config = file
|
30
|
+
end
|
31
|
+
|
32
|
+
def file(file)
|
33
|
+
validate_file file
|
34
|
+
@files.push file
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute
|
38
|
+
inspector = ::RuboCop::FileInspector.new({})
|
39
|
+
# yes, have to pass in a block
|
40
|
+
inspector.process_files files, @cfg_store do
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def description
|
46
|
+
'Runs rubocop, loads .rubocop.yml from ./'
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def files
|
52
|
+
::RuboCop::TargetFinder.new(@cfg_store).find @files
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'mixlib/shellout'
|
4
|
+
require 'singularity_dsl/stdout'
|
5
|
+
|
6
|
+
# shell-out resource for any ol commands
|
7
|
+
class ShellTask < SingularityDsl::Task
|
8
|
+
include SingularityDsl::Stdout
|
9
|
+
|
10
|
+
attr_reader :shell, :conditionals, :alternative, :no_fail
|
11
|
+
attr_writer :live_stream
|
12
|
+
|
13
|
+
def initialize(&block)
|
14
|
+
@live_stream = STDOUT
|
15
|
+
@conditionals = []
|
16
|
+
@no_fail = false
|
17
|
+
@alternative = 'echo "no alternative shell cmd defined"'
|
18
|
+
super(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def condition(cmd)
|
22
|
+
invalid_cmd 'condition' unless cmd.is_a? String
|
23
|
+
@conditionals.push cmd
|
24
|
+
end
|
25
|
+
|
26
|
+
def no_fail(switch)
|
27
|
+
fail 'no_fail must be bool' unless bool? switch
|
28
|
+
@no_fail = switch
|
29
|
+
end
|
30
|
+
|
31
|
+
def alt(cmd)
|
32
|
+
invalid_cmd 'alt' unless cmd.is_a? String
|
33
|
+
@alternative = cmd
|
34
|
+
end
|
35
|
+
|
36
|
+
def command(cmd)
|
37
|
+
@task_name = cmd
|
38
|
+
@shell = setup_shell cmd
|
39
|
+
end
|
40
|
+
|
41
|
+
def task_name
|
42
|
+
return @task_name if @task_name
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def execute
|
47
|
+
throw 'command never defined' if @shell.nil?
|
48
|
+
command @alternative unless evaluate_conditionals
|
49
|
+
@live_stream << log_shell if @live_stream
|
50
|
+
@shell.run_command
|
51
|
+
return 0 if @no_fail
|
52
|
+
@shell.exitstatus
|
53
|
+
end
|
54
|
+
|
55
|
+
def description
|
56
|
+
'Runs a SH command using Mixlib::ShellOut'
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def log_shell(pre = '', shell = false)
|
62
|
+
shell ||= @shell
|
63
|
+
pre ||= ''
|
64
|
+
log = "[ShellTask]:#{pre}:#{shell.command}"
|
65
|
+
data(log)
|
66
|
+
end
|
67
|
+
|
68
|
+
def bool?(val)
|
69
|
+
val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
70
|
+
end
|
71
|
+
|
72
|
+
def setup_shell(cmd)
|
73
|
+
shell = ::Mixlib::ShellOut.new cmd
|
74
|
+
shell.live_stream = @live_stream if @live_stream
|
75
|
+
shell
|
76
|
+
end
|
77
|
+
|
78
|
+
def invalid_cmd(type)
|
79
|
+
throw "#{type} must be string"
|
80
|
+
end
|
81
|
+
|
82
|
+
def evaluate_conditionals
|
83
|
+
@conditionals.all? do |cmd|
|
84
|
+
shell = setup_shell cmd
|
85
|
+
log_shell '[conditional]', shell
|
86
|
+
shell.run_command
|
87
|
+
!failed_status(shell.exitstatus)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'singularity_dsl/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'singularity_dsl'
|
8
|
+
spec.version = SingularityDsl::VERSION
|
9
|
+
spec.authors = ['chr0n1x']
|
10
|
+
spec.email = ['heilong24@gmail.com']
|
11
|
+
spec.description = %q{DSL for your SingularityCI instance.}
|
12
|
+
spec.summary = %q{}
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'mixlib-shellout', '~> 1.4'
|
22
|
+
spec.add_dependency 'rainbow', '~> 2.0.0'
|
23
|
+
spec.add_dependency 'rake', '~> 10.3'
|
24
|
+
spec.add_dependency 'rspec', '~> 2.6'
|
25
|
+
spec.add_dependency 'rubocop', '~> 0.23.0'
|
26
|
+
spec.add_dependency 'terminal-table', '~> 1.4'
|
27
|
+
spec.add_dependency 'thor', '~> 0.19'
|
28
|
+
|
29
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
30
|
+
spec.add_development_dependency 'gem-release'
|
31
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'singularity_dsl/application'
|
4
|
+
|
5
|
+
describe 'Application' do
|
6
|
+
let(:app) { SingularityDsl::Application.new }
|
7
|
+
|
8
|
+
context '#initialize' do
|
9
|
+
it 'creates base runner' do
|
10
|
+
expect(app.runner).to be_kind_of SingularityDsl::Dsl::Runner
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context '#load_script' do
|
15
|
+
it 'just calls runner.load_ex_script' do
|
16
|
+
stub_res = 'spooooooky ghooooost'
|
17
|
+
expect(app.runner).to(receive(:load_ex_script).and_return stub_res)
|
18
|
+
expect(app.load_script 'dummy').to eql stub_res
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context '#run' do
|
23
|
+
it 'logs resource failures' do
|
24
|
+
# don't want the entire thing to exit...
|
25
|
+
app.stub(:post_task_runner_actions)
|
26
|
+
app.runner.stub(:execute).and_raise(SingularityDsl::Errors::ResourceFail)
|
27
|
+
expect(app).to receive(:log_resource_fail)
|
28
|
+
app.run
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'runner post-script actions are evaulated on failure' do
|
32
|
+
app.stub(:post_task_runner_actions)
|
33
|
+
app.stub(:log_resource_fail)
|
34
|
+
app.runner.stub(:execute).and_raise(SingularityDsl::Errors::ResourceFail)
|
35
|
+
expect(app).to receive(:post_task_runner_actions)
|
36
|
+
app.run
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'logs resource errors' do
|
40
|
+
app.stub(:post_task_runner_actions)
|
41
|
+
app.runner.stub(:execute).and_raise(SingularityDsl::Errors::ResourceError)
|
42
|
+
expect(app).to receive(:log_resource_error)
|
43
|
+
app.run
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'runner post-script actions are evaulated on error' do
|
47
|
+
app.stub(:post_task_runner_actions)
|
48
|
+
app.stub(:log_resource_error)
|
49
|
+
app.runner.stub(:execute).and_raise(SingularityDsl::Errors::ResourceError)
|
50
|
+
expect(app).to receive(:post_task_runner_actions)
|
51
|
+
app.run
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'runner post-script actions are evaulated on error' do
|
55
|
+
app.stub(:post_task_runner_actions)
|
56
|
+
app.stub(:execute)
|
57
|
+
expect(app.runner.state).to receive :exit_code
|
58
|
+
app.run
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context '#post_task_runner_actions' do
|
63
|
+
it 'outputs warning when script fails' do
|
64
|
+
app.stub :script_warn
|
65
|
+
app.runner.stub :post_actions
|
66
|
+
app.stub :exit_run
|
67
|
+
app.runner.state.stub(:failed).and_return true
|
68
|
+
expect(app).to receive(:script_warn)
|
69
|
+
app.post_task_runner_actions
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'outputs warning when script errors' do
|
73
|
+
app.stub :script_error
|
74
|
+
app.runner.stub :post_actions
|
75
|
+
app.stub :exit_run
|
76
|
+
app.runner.state.stub(:error).and_return true
|
77
|
+
expect(app).to receive(:script_error)
|
78
|
+
app.post_task_runner_actions
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context '#change_list' do
|
83
|
+
it 'returns a sorted list' do
|
84
|
+
expect(app.change_list(%w(b c e a d)))
|
85
|
+
.to eql %w(a b c d e)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'handles empty lists' do
|
89
|
+
expect(app.change_list([])).to eql []
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|