puppet-debugger 0.6.1 → 0.7.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 +4 -4
- data/.gitignore +1 -0
- data/.gitlab-ci.yml +30 -13
- data/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +11 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +9 -0
- data/DEVELOPMENT.md +6 -1
- data/Gemfile +14 -12
- data/Plugin_development.md +304 -0
- data/README.md +4 -7
- data/Rakefile +6 -5
- data/bin/pdb +1 -0
- data/lib/awesome_print/ext/awesome_puppet.rb +1 -0
- data/lib/plugins/puppet-debugger/input_responders/benchmark.rb +40 -0
- data/lib/plugins/puppet-debugger/input_responders/classes.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/classification.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/commands.rb +95 -0
- data/lib/plugins/puppet-debugger/input_responders/datatypes.rb +17 -0
- data/lib/plugins/puppet-debugger/input_responders/environment.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/exit.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/facterdb_filter.rb +16 -0
- data/lib/plugins/puppet-debugger/input_responders/facts.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/functions.rb +15 -0
- data/lib/plugins/puppet-debugger/input_responders/help.rb +14 -0
- data/lib/plugins/puppet-debugger/input_responders/krt.rb +14 -0
- data/lib/{puppet-debugger/support → plugins/puppet-debugger/input_responders}/play.rb +37 -26
- data/lib/plugins/puppet-debugger/input_responders/reset.rb +21 -0
- data/lib/plugins/puppet-debugger/input_responders/resources.rb +22 -0
- data/lib/plugins/puppet-debugger/input_responders/set.rb +55 -0
- data/lib/plugins/puppet-debugger/input_responders/types.rb +35 -0
- data/lib/plugins/puppet-debugger/input_responders/vars.rb +18 -0
- data/lib/plugins/puppet-debugger/input_responders/whereami.rb +29 -0
- data/lib/puppet-debugger.rb +12 -1
- data/lib/puppet-debugger/cli.rb +38 -22
- data/lib/puppet-debugger/code/code_file.rb +16 -15
- data/lib/puppet-debugger/code/code_range.rb +1 -0
- data/lib/puppet-debugger/code/loc.rb +1 -0
- data/lib/puppet-debugger/debugger_code.rb +1 -0
- data/lib/puppet-debugger/hooks.rb +174 -0
- data/lib/puppet-debugger/input_responder_plugin.rb +45 -0
- data/lib/puppet-debugger/plugin_test_helper.rb +44 -0
- data/lib/puppet-debugger/support.rb +13 -9
- data/lib/puppet-debugger/support/compiler.rb +1 -0
- data/lib/puppet-debugger/support/environment.rb +2 -0
- data/lib/puppet-debugger/support/errors.rb +9 -0
- data/lib/puppet-debugger/support/facts.rb +2 -1
- data/lib/puppet-debugger/support/functions.rb +3 -1
- data/lib/puppet-debugger/support/loader.rb +2 -0
- data/lib/puppet-debugger/support/node.rb +1 -0
- data/lib/puppet-debugger/support/scope.rb +1 -0
- data/lib/puppet/application/debugger.rb +1 -0
- data/lib/version.rb +2 -1
- data/puppet-debugger.gemspec +20 -15
- data/run_container_test.sh +1 -1
- data/spec/environment_spec.rb +2 -1
- data/spec/facts_spec.rb +1 -0
- data/spec/hooks_spec.rb +341 -0
- data/spec/input_responder_plugin_spec.rb +45 -0
- data/spec/input_responders/help_spec.rb +17 -0
- data/spec/input_responders/krt_spec.rb +12 -0
- data/spec/input_responders/play_spec.rb +160 -0
- data/spec/pdb_spec.rb +1 -0
- data/spec/puppet/application/debugger_spec.rb +1 -2
- data/spec/puppet_debugger_spec.rb +49 -88
- data/spec/remote_node_spec.rb +3 -2
- data/spec/spec_helper.rb +7 -0
- data/spec/support_spec.rb +5 -116
- data/test_matrix.rb +2 -0
- metadata +65 -12
- data/Gemfile.lock +0 -95
- data/lib/puppet-debugger/support/input_responders.rb +0 -191
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'puppet-debugger/support/errors'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module PuppetDebugger
|
6
|
+
class InputResponderPlugin
|
7
|
+
include Singleton
|
8
|
+
extend Forwardable
|
9
|
+
attr_accessor :debugger
|
10
|
+
def_delegators :debugger, :scope, :node, :environment,
|
11
|
+
:add_hook, :handle_input, :delete_hook, :function_map
|
12
|
+
def_delegators :scope, :compiler, :catalog
|
13
|
+
def_delegators :node, :facts
|
14
|
+
|
15
|
+
def self.command_words
|
16
|
+
self::COMMAND_WORDS
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.summary
|
20
|
+
self::SUMMARY
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.command_group
|
24
|
+
self::COMMAND_GROUP
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.details
|
28
|
+
{ words: command_words, summary: summary, group: command_group }
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param args [Array[String]] - an array of arguments to pass to the plugin command
|
32
|
+
# @param debugger PuppetDebugger::Cli - an instance of the PuppetDebugger::Cli object
|
33
|
+
# @return the output of the plugin command
|
34
|
+
def self.execute(args = [], debugger)
|
35
|
+
instance.debugger = debugger
|
36
|
+
instance.run(args)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param args [Array[String]] - an array of arguments to pass to the plugin command
|
40
|
+
# @return the output of the plugin command
|
41
|
+
def run(args = [])
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# https://relishapp.com/rspec/rspec-core/v/3-6/docs/example-groups/shared-examples
|
2
|
+
RSpec.shared_examples "plugin_tests" do |parameter|
|
3
|
+
let(:plugin) do
|
4
|
+
instance = PuppetDebugger::InputResponders::Commands.plugin_from_command(subject.to_s).instance
|
5
|
+
instance.debugger = debugger
|
6
|
+
instance
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:output) do
|
10
|
+
StringIO.new
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:debugger) do
|
14
|
+
PuppetDebugger::Cli.new({ out_buffer: output }.merge(options))
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:options) do
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "commands contant is an array" do
|
22
|
+
expect(plugin.class::COMMAND_WORDS).to be_a(Array)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "commands must contain at least one word" do
|
26
|
+
expect(plugin.class::COMMAND_WORDS.count).to be > 0
|
27
|
+
end
|
28
|
+
|
29
|
+
it "summary must be a string" do
|
30
|
+
expect(plugin.class::SUMMARY).to be_a(String)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'implements run' do
|
34
|
+
expect{plugin.run([])}.not_to raise_error(NotImplementedError)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'be looked up via any command words' do
|
38
|
+
plugin.class::COMMAND_WORDS.each do |word|
|
39
|
+
actual = PuppetDebugger::InputResponders::Commands.plugin_from_command(word.to_s).instance.class
|
40
|
+
expect(actual).to eq(plugin.class)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'puppet/pops'
|
3
4
|
require 'facterdb'
|
4
5
|
require 'tempfile'
|
@@ -17,8 +18,6 @@ module PuppetDebugger
|
|
17
18
|
include PuppetDebugger::Support::Functions
|
18
19
|
include PuppetDebugger::Support::Node
|
19
20
|
include PuppetDebugger::Support::Loader
|
20
|
-
include PuppetDebugger::Support::InputResponders
|
21
|
-
include PuppetDebugger::Support::Play
|
22
21
|
|
23
22
|
# parses the error type into a more useful error message defined in errors.rb
|
24
23
|
# returns new error object or the original if error cannot be parsed
|
@@ -45,6 +44,10 @@ module PuppetDebugger
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
47
|
+
def static_responder_list
|
48
|
+
PuppetDebugger::InputResponders::Commands.command_list
|
49
|
+
end
|
50
|
+
|
48
51
|
# this is the lib directory of this gem
|
49
52
|
# in order to load any puppet functions from this gem we need to add the lib path
|
50
53
|
# of this gem
|
@@ -61,10 +64,6 @@ module PuppetDebugger
|
|
61
64
|
end
|
62
65
|
end
|
63
66
|
|
64
|
-
def keyword_expression
|
65
|
-
@keyword_expression ||= Regexp.new(/^exit|^:set|^play|^classification|^facts|^vars|^functions|^whereami|^classes|^resources|^krt|^environment|^reset|^help/)
|
66
|
-
end
|
67
|
-
|
68
67
|
def known_resource_types
|
69
68
|
res = {
|
70
69
|
hostclasses: scope.environment.known_resource_types.hostclasses.keys,
|
@@ -136,20 +135,25 @@ module PuppetDebugger
|
|
136
135
|
# because the repl is not a module we leave the modname blank
|
137
136
|
scope.environment.known_resource_types.import_ast(ast, '')
|
138
137
|
|
139
|
-
|
138
|
+
exec_hook :before_eval, '', self, self
|
139
|
+
if bench
|
140
140
|
result = nil
|
141
141
|
time = Benchmark.realtime do
|
142
142
|
result = parser.evaluate_string(scope, input, File.expand_path(file))
|
143
143
|
end
|
144
|
-
[result, "Time elapsed #{(time*1000).round(2)} ms"]
|
144
|
+
out = [result, "Time elapsed #{(time * 1000).round(2)} ms"]
|
145
145
|
else
|
146
|
-
parser.evaluate_string(scope, input, File.expand_path(file))
|
146
|
+
out = parser.evaluate_string(scope, input, File.expand_path(file))
|
147
147
|
end
|
148
|
+
exec_hook :after_eval, out, self, self
|
149
|
+
out
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
151
153
|
def puppet_lib_dir
|
152
154
|
# returns something like "/Library/Ruby/Gems/2.0.0/gems/puppet-4.2.2/lib/puppet.rb"
|
155
|
+
# "/Users/adam/.rbenv/versions/2.2.6/lib/ruby/gems/2.2.0/gems/puppet-4.9.4/lib"
|
156
|
+
|
153
157
|
# this is only useful when returning a namespace with the functions
|
154
158
|
@puppet_lib_dir ||= File.dirname(Puppet.method(:[]).source_location.first)
|
155
159
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module PuppetDebugger
|
3
4
|
module Support
|
4
5
|
module Environment
|
@@ -7,6 +8,7 @@ module PuppetDebugger
|
|
7
8
|
def puppet_environment
|
8
9
|
@puppet_environment ||= create_environment
|
9
10
|
end
|
11
|
+
alias :environment :puppet_environment
|
10
12
|
|
11
13
|
# returns an array of module directories, generally this is the only place
|
12
14
|
# to look for puppet code by default. This is read from the puppet configuration
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module PuppetDebugger
|
3
4
|
module Exception
|
4
5
|
class Error < StandardError
|
@@ -8,9 +9,17 @@ module PuppetDebugger
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
12
|
+
|
13
|
+
|
11
14
|
class FatalError < Error
|
12
15
|
end
|
13
16
|
|
17
|
+
class InvalidCommand < Error
|
18
|
+
def message
|
19
|
+
data[:message]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
class ConnectError < Error
|
15
24
|
def message
|
16
25
|
out = <<-EOF
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module PuppetDebugger
|
3
4
|
module Support
|
4
5
|
module Facts
|
@@ -46,7 +47,7 @@ module PuppetDebugger
|
|
46
47
|
node_facts = FacterDB.get_facts(dynamic_facterdb_filter).first
|
47
48
|
if node_facts.nil?
|
48
49
|
message = <<-EOS
|
49
|
-
Using filter: #{
|
50
|
+
Using filter: #{dynamic_facterdb_filter}
|
50
51
|
Bad FacterDB filter, please change the filter so it returns a result set.
|
51
52
|
See https://github.com/camptocamp/facterdb/#with-a-string-filter
|
52
53
|
EOS
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module PuppetDebugger
|
3
4
|
module Support
|
4
5
|
module Functions
|
@@ -43,7 +44,8 @@ module PuppetDebugger
|
|
43
44
|
obj = {}
|
44
45
|
name = File.basename(file, '.rb')
|
45
46
|
obj[:name] = name
|
46
|
-
|
47
|
+
# return the last matched in cases where rbenv might be involved
|
48
|
+
obj[:parent] = file.scan(mod_finder).flatten.last
|
47
49
|
@functions["#{obj[:parent]}::#{name}"] = obj
|
48
50
|
end
|
49
51
|
end
|
data/lib/version.rb
CHANGED
data/puppet-debugger.gemspec
CHANGED
@@ -1,37 +1,42 @@
|
|
1
1
|
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require './lib/version'
|
3
5
|
require 'date'
|
4
6
|
|
5
7
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
8
|
+
s.name = 'puppet-debugger'
|
7
9
|
s.version = PuppetDebugger::VERSION
|
8
10
|
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|resources|local_test_results|pec)/}) }
|
9
|
-
s.bindir =
|
10
|
-
s.executables = [
|
11
|
+
s.bindir = 'bin'
|
12
|
+
s.executables = ['pdb']
|
11
13
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
12
14
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
13
15
|
if s.respond_to?(:metadata)
|
14
16
|
s.metadata['allowed_push_host'] = 'https://rubygems.org'
|
15
17
|
else
|
16
|
-
raise
|
18
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
17
19
|
end
|
18
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
19
|
-
s.require_paths = [
|
20
|
-
s.authors = [
|
20
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
21
|
+
s.require_paths = ['lib']
|
22
|
+
s.authors = ['Corey Osman']
|
21
23
|
s.date = DateTime.now.strftime('%Y-%m-%d')
|
22
|
-
s.description =
|
23
|
-
s.email =
|
24
|
+
s.description = 'A interactive command line tool for evaluating and debugging the puppet language'
|
25
|
+
s.email = 'corey@nwops.io'
|
24
26
|
s.extra_rdoc_files = [
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
'CHANGELOG.md',
|
28
|
+
'LICENSE.txt',
|
29
|
+
'README.md'
|
28
30
|
]
|
29
31
|
s.homepage = "http://github.com/nwops/puppet-debugger"
|
30
32
|
s.licenses = ["MIT"]
|
31
33
|
s.rubygems_version = "2.4.5.1"
|
32
34
|
s.summary = "A repl based debugger for the puppet language"
|
35
|
+
s.add_runtime_dependency(%q<pluginator>, ["~> 1.4.1"])
|
33
36
|
s.add_runtime_dependency(%q<puppet>, [">= 3.8"])
|
34
|
-
s.add_runtime_dependency(%q<facterdb>, ["
|
35
|
-
s.add_runtime_dependency(%q<awesome_print>, ["~> 1.
|
37
|
+
s.add_runtime_dependency(%q<facterdb>, ["~> 0.3.1"])
|
38
|
+
s.add_runtime_dependency(%q<awesome_print>, ["~> 1.7"])
|
36
39
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
37
|
-
|
40
|
+
s.add_development_dependency(%q<rspec>, ["~> 3.6"])
|
41
|
+
|
42
|
+
end
|
data/run_container_test.sh
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
export PATH=$PATH:/usr/local/bundle
|
3
3
|
gem install bundler > /dev/null
|
4
4
|
gem update --system > /dev/null
|
5
|
-
bundle
|
5
|
+
bundle update
|
6
6
|
bundle exec puppet module install puppetlabs-stdlib
|
7
7
|
echo "Running tests, output to ${OUT_DIR}/results.txt"
|
8
8
|
bundle exec rspec --out "${OUT_DIR}/results.txt" --format documentation
|
data/spec/environment_spec.rb
CHANGED
data/spec/facts_spec.rb
CHANGED
data/spec/hooks_spec.rb
ADDED
@@ -0,0 +1,341 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe PuppetDebugger::Hooks do
|
4
|
+
before do
|
5
|
+
@hooks = PuppetDebugger::Hooks.new
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:output) do
|
9
|
+
StringIO.new
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:debugger) do
|
13
|
+
PuppetDebugger::Cli.new(out_buffer: output)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "adding a new hook" do
|
17
|
+
it 'should not execute hook while adding it' do
|
18
|
+
run = false
|
19
|
+
@hooks.add_hook(:test_hook, :my_name) { run = true }
|
20
|
+
expect(run).to eq false
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should not allow adding of a hook with a duplicate name' do
|
24
|
+
@hooks.add_hook(:test_hook, :my_name) {}
|
25
|
+
|
26
|
+
expect { @hooks.add_hook(:test_hook, :my_name) {} }.to raise_error ArgumentError
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should create a new hook with a block' do
|
30
|
+
@hooks.add_hook(:test_hook, :my_name) { }
|
31
|
+
expect(@hooks.hook_count(:test_hook)).to eq 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should create a new hook with a callable' do
|
35
|
+
@hooks.add_hook(:test_hook, :my_name, proc { })
|
36
|
+
expect(@hooks.hook_count(:test_hook)).to eq 1
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should use block if given both block and callable' do
|
40
|
+
run = false
|
41
|
+
foo = false
|
42
|
+
@hooks.add_hook(:test_hook, :my_name, proc { foo = true }) { run = true }
|
43
|
+
expect(@hooks.hook_count(:test_hook)).to eq 1
|
44
|
+
@hooks.exec_hook(:test_hook)
|
45
|
+
expect(run).to eq true
|
46
|
+
expect(foo).to eq false
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should raise if not given a block or any other object' do
|
50
|
+
expect { @hooks.add_hook(:test_hook, :my_name) }.to raise_error ArgumentError
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should create multiple hooks for an event' do
|
54
|
+
@hooks.add_hook(:test_hook, :my_name) {}
|
55
|
+
@hooks.add_hook(:test_hook, :my_name2) {}
|
56
|
+
expect(@hooks.hook_count(:test_hook)).to eq 2
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return a count of 0 for an empty hook' do
|
60
|
+
expect(@hooks.hook_count(:test_hook)).to eq 0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "PuppetDebugger::Hooks#merge" do
|
65
|
+
describe "merge!" do
|
66
|
+
it 'should merge in the PuppetDebugger::Hooks' do
|
67
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
68
|
+
h2 = PuppetDebugger::Hooks.new
|
69
|
+
|
70
|
+
h2.merge!(h1)
|
71
|
+
expect(h2.get_hook(:test_hook, :testing)).to eq h1.get_hook(:test_hook, :testing)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should not share merged elements with original' do
|
75
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
76
|
+
h2 = PuppetDebugger::Hooks.new
|
77
|
+
|
78
|
+
h2.merge!(h1)
|
79
|
+
h2.add_hook(:test_hook, :testing2) {}
|
80
|
+
expect(h2.get_hook(:test_hook, :testing2)).not_to eq h1.get_hook(:test_hook, :testing2)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should NOT overwrite hooks belonging to shared event in receiver' do
|
84
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
85
|
+
callable = proc {}
|
86
|
+
h2 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing2, callable)
|
87
|
+
|
88
|
+
h2.merge!(h1)
|
89
|
+
expect(h2.get_hook(:test_hook, :testing2)).to eq callable
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should overwrite identical hook in receiver' do
|
93
|
+
callable1 = proc { :one }
|
94
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing, callable1)
|
95
|
+
callable2 = proc { :two }
|
96
|
+
h2 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing, callable2)
|
97
|
+
|
98
|
+
h2.merge!(h1)
|
99
|
+
expect(h2.get_hook(:test_hook, :testing)).to eq callable1
|
100
|
+
expect(h2.hook_count(:test_hook)).to eq 1
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should preserve hook order' do
|
104
|
+
name = ""
|
105
|
+
h1 = PuppetDebugger::Hooks.new
|
106
|
+
h1.add_hook(:test_hook, :testing3) { name << "h" }
|
107
|
+
h1.add_hook(:test_hook, :testing4) { name << "n" }
|
108
|
+
|
109
|
+
h2 = PuppetDebugger::Hooks.new
|
110
|
+
h2.add_hook(:test_hook, :testing1) { name << "j" }
|
111
|
+
h2.add_hook(:test_hook, :testing2) { name << "o" }
|
112
|
+
|
113
|
+
h2.merge!(h1)
|
114
|
+
h2.exec_hook(:test_hook)
|
115
|
+
|
116
|
+
expect(name).to eq "john"
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "merge" do
|
120
|
+
it 'should return a fresh, independent instance' do
|
121
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
122
|
+
h2 = PuppetDebugger::Hooks.new
|
123
|
+
|
124
|
+
h3 = h2.merge(h1)
|
125
|
+
expect(h3).not_to eq h1
|
126
|
+
expect(h3).not_to eq h2
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should contain hooks from original instance' do
|
130
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
131
|
+
h2 = PuppetDebugger::Hooks.new.add_hook(:test_hook2, :testing) {}
|
132
|
+
|
133
|
+
h3 = h2.merge(h1)
|
134
|
+
expect(h3.get_hook(:test_hook, :testing)).to eq h1.get_hook(:test_hook, :testing)
|
135
|
+
expect(h3.get_hook(:test_hook2, :testing)).to eq h2.get_hook(:test_hook2, :testing)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should not affect original instances when new hooks are added' do
|
139
|
+
h1 = PuppetDebugger::Hooks.new.add_hook(:test_hook, :testing) {}
|
140
|
+
h2 = PuppetDebugger::Hooks.new.add_hook(:test_hook2, :testing) {}
|
141
|
+
|
142
|
+
h3 = h2.merge(h1)
|
143
|
+
h3.add_hook(:test_hook3, :testing) {}
|
144
|
+
|
145
|
+
expect(h1.get_hook(:test_hook3, :testing)).to eq nil
|
146
|
+
expect(h2.get_hook(:test_hook3, :testing)).to eq nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "dupping a PuppetDebugger::Hooks instance" do
|
154
|
+
it 'should share hooks with original' do
|
155
|
+
@hooks.add_hook(:test_hook, :testing) do
|
156
|
+
:none_such
|
157
|
+
end
|
158
|
+
|
159
|
+
hooks_dup = @hooks.dup
|
160
|
+
expect(hooks_dup.get_hook(:test_hook, :testing)).to eq @hooks.get_hook(:test_hook, :testing)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'adding a new event to dupped instance should not affect original' do
|
164
|
+
@hooks.add_hook(:test_hook, :testing) { :none_such }
|
165
|
+
hooks_dup = @hooks.dup
|
166
|
+
|
167
|
+
hooks_dup.add_hook(:other_test_hook, :testing) { :okay_man }
|
168
|
+
|
169
|
+
expect(hooks_dup.get_hook(:other_test_hook, :testing)).not_to eq @hooks.get_hook(:other_test_hook, :testing)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'adding a new hook to dupped instance should not affect original' do
|
173
|
+
@hooks.add_hook(:test_hook, :testing) { :none_such }
|
174
|
+
hooks_dup = @hooks.dup
|
175
|
+
|
176
|
+
hooks_dup.add_hook(:test_hook, :testing2) { :okay_man }
|
177
|
+
|
178
|
+
expect(hooks_dup.get_hook(:test_hook, :testing2)).not_to eq @hooks.get_hook(:test_hook, :testing2)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "getting hooks" do
|
184
|
+
describe "get_hook" do
|
185
|
+
it 'should return the correct requested hook' do
|
186
|
+
run = false
|
187
|
+
fun = false
|
188
|
+
@hooks.add_hook(:test_hook, :my_name) { run = true }
|
189
|
+
@hooks.add_hook(:test_hook, :my_name2) { fun = true }
|
190
|
+
@hooks.get_hook(:test_hook, :my_name).call
|
191
|
+
expect(run).to eq true
|
192
|
+
expect(fun).to eq false
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should return nil if hook does not exist' do
|
196
|
+
expect(@hooks.get_hook(:test_hook, :my_name)).to eq nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "get_hooks" do
|
201
|
+
it 'should return a hash of hook names/hook functions for an event' do
|
202
|
+
hook1 = proc { 1 }
|
203
|
+
hook2 = proc { 2 }
|
204
|
+
@hooks.add_hook(:test_hook, :my_name1, hook1)
|
205
|
+
@hooks.add_hook(:test_hook, :my_name2, hook2)
|
206
|
+
hash = @hooks.get_hooks(:test_hook)
|
207
|
+
expect(hash.size).to eq 2
|
208
|
+
expect(hash[:my_name1]).to eq hook1
|
209
|
+
expect(hash[:my_name2]).to eq hook2
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should return an empty hash if no hooks defined' do
|
213
|
+
expect(@hooks.get_hooks(:test_hook)).to eq({})
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "clearing all hooks for an event" do
|
219
|
+
it 'should clear all hooks' do
|
220
|
+
@hooks.add_hook(:test_hook, :my_name) { }
|
221
|
+
@hooks.add_hook(:test_hook, :my_name2) { }
|
222
|
+
@hooks.add_hook(:test_hook, :my_name3) { }
|
223
|
+
@hooks.clear_event_hooks(:test_hook)
|
224
|
+
expect(@hooks.hook_count(:test_hook)).to eq 0
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "deleting a hook" do
|
229
|
+
it 'should successfully delete a hook' do
|
230
|
+
@hooks.add_hook(:test_hook, :my_name) {}
|
231
|
+
@hooks.delete_hook(:test_hook, :my_name)
|
232
|
+
expect(@hooks.hook_count(:test_hook)).to eq 0
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should return the deleted hook' do
|
236
|
+
run = false
|
237
|
+
@hooks.add_hook(:test_hook, :my_name) { run = true }
|
238
|
+
@hooks.delete_hook(:test_hook, :my_name).call
|
239
|
+
expect(run).to eq true
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'should return nil if hook does not exist' do
|
243
|
+
expect(@hooks.delete_hook(:test_hook, :my_name)).to eq nil
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "executing a hook" do
|
248
|
+
it 'should execute block hook' do
|
249
|
+
run = false
|
250
|
+
@hooks.add_hook(:test_hook, :my_name) { run = true }
|
251
|
+
@hooks.exec_hook(:test_hook)
|
252
|
+
expect(run).to eq true
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'should execute proc hook' do
|
256
|
+
run = false
|
257
|
+
@hooks.add_hook(:test_hook, :my_name, proc { run = true })
|
258
|
+
@hooks.exec_hook(:test_hook)
|
259
|
+
expect(run).to eq true
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'should execute a general callable hook' do
|
263
|
+
callable = Object.new.tap do |obj|
|
264
|
+
obj.instance_variable_set(:@test_var, nil)
|
265
|
+
class << obj
|
266
|
+
attr_accessor :test_var
|
267
|
+
def call() @test_var = true; end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
@hooks.add_hook(:test_hook, :my_name, callable)
|
272
|
+
@hooks.exec_hook(:test_hook)
|
273
|
+
expect(callable.test_var).to eq true
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should execute all hooks for an event if more than one is defined' do
|
277
|
+
x = nil
|
278
|
+
y = nil
|
279
|
+
@hooks.add_hook(:test_hook, :my_name1) { y = true }
|
280
|
+
@hooks.add_hook(:test_hook, :my_name2) { x = true }
|
281
|
+
@hooks.exec_hook(:test_hook)
|
282
|
+
expect(x).to eq true
|
283
|
+
expect(y).to eq true
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should execute hooks in order' do
|
287
|
+
array = []
|
288
|
+
@hooks.add_hook(:test_hook, :my_name1) { array << 1 }
|
289
|
+
@hooks.add_hook(:test_hook, :my_name2) { array << 2 }
|
290
|
+
@hooks.add_hook(:test_hook, :my_name3) { array << 3 }
|
291
|
+
@hooks.exec_hook(:test_hook)
|
292
|
+
expect(array).to eq [1, 2, 3]
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'return value of exec_hook should be that of last executed hook' do
|
296
|
+
@hooks.add_hook(:test_hook, :my_name1) { 1 }
|
297
|
+
@hooks.add_hook(:test_hook, :my_name2) { 2 }
|
298
|
+
@hooks.add_hook(:test_hook, :my_name3) { 3 }
|
299
|
+
expect(@hooks.exec_hook(:test_hook)).to eq 3
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should add exceptions to the errors array' do
|
303
|
+
@hooks.add_hook(:test_hook, :foo1) { raise 'one' }
|
304
|
+
@hooks.add_hook(:test_hook, :foo2) { raise 'two' }
|
305
|
+
@hooks.add_hook(:test_hook, :foo3) { raise 'three' }
|
306
|
+
@hooks.exec_hook(:test_hook)
|
307
|
+
expect(@hooks.errors.map(&:message)).to eq ['one', 'two', 'three']
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should return the last exception raised as the return value' do
|
311
|
+
@hooks.add_hook(:test_hook, :foo1) { raise 'one' }
|
312
|
+
@hooks.add_hook(:test_hook, :foo2) { raise 'two' }
|
313
|
+
@hooks.add_hook(:test_hook, :foo3) { raise 'three' }
|
314
|
+
expect(@hooks.exec_hook(:test_hook)).to eq @hooks.errors.last
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe "anonymous hooks" do
|
319
|
+
it 'should allow adding of hook without a name' do
|
320
|
+
@hooks.add_hook(:test_hook, nil) {}
|
321
|
+
expect(@hooks.hook_count(:test_hook)).to eq 1
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'should only allow one anonymous hook to exist' do
|
325
|
+
@hooks.add_hook(:test_hook, nil) { }
|
326
|
+
@hooks.add_hook(:test_hook, nil) { }
|
327
|
+
expect(@hooks.hook_count(:test_hook)).to eq 1
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'should execute most recently added anonymous hook' do
|
331
|
+
x = nil
|
332
|
+
y = nil
|
333
|
+
@hooks.add_hook(:test_hook, nil) { y = 1 }
|
334
|
+
@hooks.add_hook(:test_hook, nil) { x = 2 }
|
335
|
+
@hooks.exec_hook(:test_hook)
|
336
|
+
expect(y).to eq nil
|
337
|
+
expect(x).to eq 2
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|