dredd_hooks 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 +4 -4
- data/CHANGELOG.md +38 -0
- data/LICENSE.txt +3 -3
- data/README.md +100 -26
- data/Rakefile +31 -0
- data/bin/dredd-hooks-ruby +3 -13
- data/doc/README.md +26 -0
- data/features/execution_order.feature +9 -8
- data/features/failing_transaction.feature +1 -0
- data/features/hook_handlers.feature +1 -0
- data/features/multiple_hookfiles.feature +4 -1
- data/features/support/env.rb +2 -5
- data/lib/dredd_hooks.rb +4 -5
- data/lib/dredd_hooks/cli.rb +18 -0
- data/lib/dredd_hooks/definitions.rb +30 -0
- data/lib/dredd_hooks/errors.rb +15 -0
- data/lib/dredd_hooks/file_loader.rb +12 -10
- data/lib/dredd_hooks/methods.rb +43 -37
- data/lib/dredd_hooks/runner.rb +113 -56
- data/lib/dredd_hooks/server.rb +53 -63
- data/lib/dredd_hooks/server/buffer.rb +49 -0
- data/lib/dredd_hooks/server/events_handler.rb +33 -0
- data/lib/dredd_hooks/version.rb +1 -1
- data/spec/integration/definitions_consistency_spec.rb +38 -0
- data/spec/lib/dredd_hooks/methods_spec.rb +62 -0
- data/spec/lib/dredd_hooks/runner_spec.rb +41 -0
- data/spec/lib/dredd_hooks/server/buffer_spec.rb +58 -0
- data/spec/lib/dredd_hooks/server/events_handler_spec.rb +50 -0
- data/spec/spec_helper.rb +35 -0
- metadata +41 -25
- data/.gitignore +0 -15
- data/.travis.yml +0 -9
- data/dredd_hooks.gemspec +0 -25
- data/features/tcp_server.feature +0 -66
@@ -0,0 +1,30 @@
|
|
1
|
+
module DreddHooks
|
2
|
+
|
3
|
+
HOOKS_ON_SINGLE_TRANSACTIONS = [:before, :before_validation, :after]
|
4
|
+
|
5
|
+
HOOKS_ON_MULTIPLE_TRANSACTIONS = [:before_each, :before_each_validation,
|
6
|
+
:after_each, :before_all, :after_all]
|
7
|
+
|
8
|
+
Server::EVENTS = {
|
9
|
+
beforeEach: [
|
10
|
+
:before_each,
|
11
|
+
:before,
|
12
|
+
],
|
13
|
+
beforeEachValidation: [
|
14
|
+
:before_each_validation,
|
15
|
+
:before_validation,
|
16
|
+
],
|
17
|
+
afterEach: [
|
18
|
+
:after,
|
19
|
+
:after_each,
|
20
|
+
],
|
21
|
+
afterAll: [
|
22
|
+
:after_all,
|
23
|
+
],
|
24
|
+
beforeAll: [
|
25
|
+
:before_all,
|
26
|
+
],
|
27
|
+
}
|
28
|
+
|
29
|
+
end
|
30
|
+
|
@@ -1,18 +1,20 @@
|
|
1
1
|
module DreddHooks
|
2
2
|
module FileLoader
|
3
|
-
def self.unique_paths globs
|
4
|
-
paths = []
|
5
|
-
globs.each do |glob|
|
6
|
-
paths += Dir.glob glob
|
7
|
-
end
|
8
|
-
paths.uniq
|
9
|
-
end
|
10
3
|
|
11
|
-
def self.load
|
12
|
-
|
4
|
+
def self.load(patterns)
|
5
|
+
unique_paths(patterns).each do |path|
|
13
6
|
puts path
|
14
7
|
require path
|
15
8
|
end
|
16
9
|
end
|
10
|
+
|
11
|
+
|
12
|
+
def self.unique_paths(patterns)
|
13
|
+
patterns.inject([]) { |paths, pattern|
|
14
|
+
paths + Dir.glob(pattern)
|
15
|
+
}.uniq
|
16
|
+
end
|
17
|
+
private_class_method :unique_paths
|
17
18
|
end
|
18
|
-
end
|
19
|
+
end
|
20
|
+
|
data/lib/dredd_hooks/methods.rb
CHANGED
@@ -1,53 +1,59 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
@@before_hooks = {}
|
4
|
-
@@before_validation_hooks = {}
|
5
|
-
@@after_hooks = {}
|
1
|
+
require 'dredd_hooks/definitions'
|
2
|
+
require 'dredd_hooks/runner'
|
6
3
|
|
7
|
-
|
8
|
-
@@before_each_validation_hooks = []
|
9
|
-
@@after_each_hooks = []
|
4
|
+
module DreddHooks
|
10
5
|
|
11
|
-
|
12
|
-
|
6
|
+
# The Ruby hooks API
|
7
|
+
module Methods
|
13
8
|
|
9
|
+
# Define hook methods in the form of:
|
14
10
|
#
|
15
|
-
#
|
11
|
+
# def before(transaction_name, &block)
|
12
|
+
# runner.register_before_hook(transaction_name, &block)
|
13
|
+
# end
|
16
14
|
#
|
15
|
+
# Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
|
16
|
+
#
|
17
|
+
# Returns nothing.
|
18
|
+
def self.define_hooks_on_single_transactions
|
19
|
+
HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
21
|
+
define_method hook_name do |transaction_name, &block|
|
22
|
+
runner.send("register_#{hook_name}_hook", transaction_name, &block)
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
@@before_validation_hooks[transaction_name] = [] if @@before_validation_hooks[transaction_name].nil?
|
25
|
-
@@before_validation_hooks[transaction_name].push block
|
25
|
+
end
|
26
26
|
end
|
27
|
+
private_class_method :define_hooks_on_single_transactions
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
# Define hook methods in the form of:
|
30
|
+
#
|
31
|
+
# def before_all(&block)
|
32
|
+
# runner.register_before_all_hook(&block)
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
|
36
|
+
#
|
37
|
+
# Returns nothing.
|
38
|
+
def self.define_hooks_on_multiple_transactions
|
39
|
+
HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
41
|
+
define_method hook_name do |&block|
|
42
|
+
runner.send("register_#{hook_name}_hook", &block)
|
43
|
+
end
|
36
44
|
|
37
|
-
|
38
|
-
@@before_each_validation_hooks.push block
|
45
|
+
end
|
39
46
|
end
|
47
|
+
private_class_method :define_hooks_on_multiple_transactions
|
40
48
|
|
41
|
-
|
42
|
-
|
43
|
-
end
|
49
|
+
define_hooks_on_single_transactions
|
50
|
+
define_hooks_on_multiple_transactions
|
44
51
|
|
45
|
-
|
46
|
-
@@before_all_hooks.push block
|
47
|
-
end
|
52
|
+
private
|
48
53
|
|
49
|
-
|
50
|
-
|
51
|
-
|
54
|
+
def runner
|
55
|
+
Runner.instance
|
56
|
+
end
|
52
57
|
end
|
53
|
-
end
|
58
|
+
end
|
59
|
+
|
data/lib/dredd_hooks/runner.rb
CHANGED
@@ -1,84 +1,141 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require 'dredd_hooks/definitions'
|
4
|
+
|
1
5
|
module DreddHooks
|
2
|
-
module Runner
|
3
6
|
|
7
|
+
# The Ruby hooks runner stores and runs the Ruby hooks
|
8
|
+
#
|
9
|
+
# It provides registration methods to be used from the DSL,
|
10
|
+
# as well as methods to run hooks by name from the server.
|
11
|
+
#
|
12
|
+
# All these methods are generated automatically according
|
13
|
+
# to the hooks definitions.
|
14
|
+
#
|
15
|
+
# Note that this class is a Singleton. Use Runner.instance to
|
16
|
+
# get references to its unique instance.
|
17
|
+
class Runner
|
18
|
+
|
19
|
+
include Singleton
|
20
|
+
|
21
|
+
# Define registration methods in the form of:
|
4
22
|
#
|
5
|
-
#
|
23
|
+
# def register_before_hook(transction_name, &block)
|
24
|
+
# hooks = @before_hooks || {}
|
25
|
+
# transaction_hooks = hooks.fetch(transaction_name, [])
|
26
|
+
# transaction_hooks.push(block)
|
27
|
+
# hooks[transaction_name] = transaction_hooks
|
28
|
+
# @before_hooks = hooks
|
29
|
+
# end
|
6
30
|
#
|
31
|
+
# Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
|
32
|
+
#
|
33
|
+
# Returns nothing.
|
34
|
+
def self.define_registration_methods_for_hooks_on_single_transactions
|
35
|
+
HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
|
7
36
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
37
|
+
define_method "register_#{hook_name}_hook" do |transaction_name, &block|
|
38
|
+
hooks = instance_variable_get("@#{hook_name}_hooks") || {}
|
39
|
+
transaction_hooks = hooks.fetch(transaction_name, [])
|
40
|
+
transaction_hooks.push(block)
|
41
|
+
hooks[transaction_name] = transaction_hooks
|
42
|
+
instance_variable_set("@#{hook_name}_hooks", hooks)
|
14
43
|
end
|
15
|
-
end
|
16
|
-
return transaction
|
17
|
-
end
|
18
44
|
|
19
|
-
def self.run_before_validation_hooks_for_transaction transaction
|
20
|
-
transaction_name = transaction["name"]
|
21
|
-
hooks = Methods.class_variable_get("@@before_validation_hooks")[transaction_name]
|
22
|
-
if hooks.kind_of? Array
|
23
|
-
hooks.each do |hook_proc|
|
24
|
-
hook_proc.call transaction
|
25
|
-
end
|
26
45
|
end
|
27
|
-
return transaction
|
28
46
|
end
|
47
|
+
private_class_method :define_registration_methods_for_hooks_on_single_transactions
|
29
48
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
# Define registration methods in the form of:
|
50
|
+
#
|
51
|
+
# def register_before_all_hook(&block)
|
52
|
+
# hooks = @before_hooks || []
|
53
|
+
# hooks.push(block)
|
54
|
+
# @before_all_hooks = hooks
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
|
58
|
+
#
|
59
|
+
# Returns nothing.
|
60
|
+
def self.define_registration_methods_for_hooks_on_multiple_transactions
|
61
|
+
HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
|
62
|
+
|
63
|
+
define_method "register_#{hook_name}_hook" do |&block|
|
64
|
+
hooks = instance_variable_get("@#{hook_name}_hooks") || []
|
65
|
+
hooks.push(block)
|
66
|
+
instance_variable_set("@#{hook_name}_hooks", hooks)
|
36
67
|
end
|
68
|
+
|
37
69
|
end
|
38
|
-
return transaction
|
39
70
|
end
|
71
|
+
private_class_method :define_registration_methods_for_hooks_on_multiple_transactions
|
40
72
|
|
73
|
+
# Define runner methods in the form of:
|
41
74
|
#
|
42
|
-
#
|
75
|
+
# def run_before_hooks_for_transaction(transaction)
|
76
|
+
# hooks = @before_hooks || {}
|
77
|
+
# transaction_name = transaction['name']
|
78
|
+
# transaction_hooks = hooks.fetch(transaction_name, [])
|
79
|
+
# transaction_hooks.each do |hook|
|
80
|
+
# hook.call(transaction)
|
81
|
+
# end
|
82
|
+
# return transaction
|
83
|
+
# end
|
43
84
|
#
|
85
|
+
# Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
|
86
|
+
#
|
87
|
+
# Returns nothing.
|
88
|
+
def self.define_runners_for_hooks_on_single_transactions
|
89
|
+
HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
|
44
90
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
hook_proc.call transaction
|
55
|
-
end
|
56
|
-
return transaction
|
57
|
-
end
|
91
|
+
define_method "run_#{hook_name}_hooks_for_transaction" do |transaction|
|
92
|
+
hooks = instance_variable_get("@#{hook_name}_hooks") || {}
|
93
|
+
transaction_name = transaction['name']
|
94
|
+
transaction_hooks = hooks.fetch(transaction_name, [])
|
95
|
+
transaction_hooks.each do |hook|
|
96
|
+
hook.call(transaction)
|
97
|
+
end
|
98
|
+
return transaction
|
99
|
+
end
|
58
100
|
|
59
|
-
def self.run_after_each_hooks_for_transaction transaction
|
60
|
-
Methods.class_variable_get("@@after_each_hooks").each do |hook_proc|
|
61
|
-
hook_proc.call transaction
|
62
101
|
end
|
63
|
-
return transaction
|
64
102
|
end
|
103
|
+
private_class_method :define_runners_for_hooks_on_single_transactions
|
65
104
|
|
105
|
+
# Define runner methods in the form of:
|
106
|
+
#
|
107
|
+
# def run_before_all_hooks_for_transaction(transaction)
|
108
|
+
# hooks = @before_all_hooks || []
|
109
|
+
# hooks.each do |hook|
|
110
|
+
# hook.call(transaction)
|
111
|
+
# end
|
112
|
+
# return transaction
|
113
|
+
# end
|
66
114
|
#
|
67
|
-
#
|
115
|
+
# Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
|
68
116
|
#
|
117
|
+
# Returns nothing.
|
118
|
+
def self.define_runners_for_hooks_on_multiple_transactions
|
119
|
+
HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
|
69
120
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
121
|
+
define_method "run_#{hook_name}_hooks_for_transaction" do |transaction|
|
122
|
+
hooks = instance_variable_get("@#{hook_name}_hooks") || []
|
123
|
+
hooks.each do |hook|
|
124
|
+
hook.call(transaction)
|
125
|
+
end
|
126
|
+
return transaction
|
127
|
+
end
|
76
128
|
|
77
|
-
def self.run_after_all_hooks_for_transactions transactions
|
78
|
-
Methods.class_variable_get("@@after_all_hooks").each do |hook_proc|
|
79
|
-
hook_proc.call transactions
|
80
129
|
end
|
81
|
-
return transactions
|
82
130
|
end
|
131
|
+
private_class_method :define_runners_for_hooks_on_multiple_transactions
|
132
|
+
|
133
|
+
define_registration_methods_for_hooks_on_single_transactions
|
134
|
+
define_registration_methods_for_hooks_on_multiple_transactions
|
135
|
+
|
136
|
+
define_runners_for_hooks_on_single_transactions
|
137
|
+
define_runners_for_hooks_on_multiple_transactions
|
138
|
+
|
83
139
|
end
|
84
|
-
end
|
140
|
+
end
|
141
|
+
|
data/lib/dredd_hooks/server.rb
CHANGED
@@ -1,86 +1,76 @@
|
|
1
1
|
require 'socket'
|
2
|
-
|
2
|
+
|
3
|
+
require 'dredd_hooks/server/buffer'
|
4
|
+
require 'dredd_hooks/server/events_handler'
|
3
5
|
|
4
6
|
module DreddHooks
|
7
|
+
|
8
|
+
# The hooks worker server
|
5
9
|
class Server
|
6
|
-
|
7
|
-
|
8
|
-
|
10
|
+
|
11
|
+
attr_reader :buffer, :error, :events_handler, :out, :server
|
12
|
+
private :buffer, :error, :events_handler, :out, :server
|
9
13
|
|
10
14
|
HOST = '127.0.0.1'
|
11
15
|
PORT = 61321
|
12
16
|
MESSAGE_DELIMITER = "\n"
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if event == "beforeEach"
|
21
|
-
data = DreddHooks::Runner.run_before_each_hooks_for_transaction data
|
22
|
-
data = DreddHooks::Runner.run_before_hooks_for_transaction data
|
23
|
-
end
|
24
|
-
|
25
|
-
if event == "beforeEachValidation"
|
26
|
-
data = DreddHooks::Runner.run_before_each_validation_hooks_for_transaction data
|
27
|
-
data = DreddHooks::Runner.run_before_validation_hooks_for_transaction data
|
28
|
-
end
|
29
|
-
|
30
|
-
if event == "afterEach"
|
31
|
-
data = DreddHooks::Runner.run_after_hooks_for_transaction data
|
32
|
-
data = DreddHooks::Runner.run_after_each_hooks_for_transaction data
|
33
|
-
end
|
34
|
-
|
35
|
-
if event == "beforeAll"
|
36
|
-
data = DreddHooks::Runner.run_before_all_hooks_for_transactions data
|
37
|
-
end
|
38
|
-
|
39
|
-
if event == "afterAll"
|
40
|
-
data = DreddHooks::Runner.run_after_all_hooks_for_transactions data
|
41
|
-
end
|
42
|
-
|
43
|
-
to_send = {
|
44
|
-
"uuid" => message['uuid'],
|
45
|
-
"event" => event,
|
46
|
-
"data" => data
|
47
|
-
}.to_json
|
48
|
-
client.puts to_send + "\n"
|
18
|
+
def initialize(error=STDERR, out=STDOUT)
|
19
|
+
@error = error
|
20
|
+
@out = out
|
21
|
+
@server = TCPServer.new(HOST, PORT)
|
22
|
+
@buffer = Buffer.new(MESSAGE_DELIMITER)
|
23
|
+
@events_handler = EventsHandler.new
|
49
24
|
end
|
50
25
|
|
51
26
|
def run
|
52
|
-
|
27
|
+
disable_buffering(out)
|
53
28
|
loop do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
buffer = ""
|
29
|
+
client = server.accept
|
30
|
+
out.puts 'Dredd connected to Ruby Dredd hooks worker'
|
31
|
+
buffer.flush!
|
58
32
|
while (data = client.recv(10))
|
59
|
-
buffer
|
60
|
-
if buffer.
|
61
|
-
|
62
|
-
buffer = ""
|
63
|
-
|
64
|
-
messages = []
|
65
|
-
|
66
|
-
splitted_buffer.each do |message|
|
67
|
-
begin
|
68
|
-
messages.push JSON.parse(message)
|
69
|
-
|
70
|
-
rescue JSON::ParserError
|
71
|
-
# if message aftger delimiter is not parseable json, it's
|
72
|
-
# a chunk of next message, put it back to the buffer
|
73
|
-
buffer += message
|
74
|
-
end
|
75
|
-
end
|
33
|
+
buffer << data
|
34
|
+
if buffer.any_message?
|
35
|
+
messages = buffer.unshift_messages
|
76
36
|
|
77
37
|
messages.each do |message|
|
78
|
-
process_message
|
38
|
+
response = process_message(message)
|
39
|
+
client.puts response + MESSAGE_DELIMITER
|
79
40
|
end
|
80
41
|
end
|
81
42
|
end
|
82
43
|
client.close
|
83
44
|
end
|
84
45
|
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Write to a file (e.g. STDOUT) without delay
|
50
|
+
#
|
51
|
+
# See https://stackoverflow.com/q/23001033
|
52
|
+
# and http://ruby-doc.org/core-2.3.1/IO.html#method-i-sync-3D
|
53
|
+
def disable_buffering(file)
|
54
|
+
file.sync = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def process_message(message)
|
58
|
+
event = message['event']
|
59
|
+
transaction = message['data']
|
60
|
+
|
61
|
+
transaction = events_handler.handle(event, transaction)
|
62
|
+
|
63
|
+
response(message['uuid'], event, transaction)
|
64
|
+
end
|
65
|
+
|
66
|
+
def response(message_uuid, event, transaction)
|
67
|
+
{
|
68
|
+
uuid: message_uuid,
|
69
|
+
event: event,
|
70
|
+
data: transaction,
|
71
|
+
}.to_json
|
72
|
+
end
|
73
|
+
|
85
74
|
end
|
86
|
-
end
|
75
|
+
end
|
76
|
+
|