elasticsearch-extensions 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +119 -1
- data/Rakefile +4 -6
- data/elasticsearch-extensions.gemspec +1 -0
- data/lib/elasticsearch/extensions/test/cluster.rb +251 -0
- data/lib/elasticsearch/extensions/test/profiling.rb +98 -0
- data/lib/elasticsearch/extensions/test/startup_shutdown.rb +54 -0
- data/lib/elasticsearch/extensions/version.rb +1 -1
- metadata +21 -2
data/README.md
CHANGED
@@ -19,7 +19,125 @@ Display a table with the output of the `_analyze` API:
|
|
19
19
|
require 'elasticsearch/extensions/ansi'
|
20
20
|
puts Elasticsearch::Client.new.indices.analyze(text: 'Quick Brown Fox Jumped').to_ansi
|
21
21
|
|
22
|
-
[Full documentation](http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/ANSI)
|
22
|
+
[Full documentation](http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/ANSI)
|
23
|
+
|
24
|
+
### Test::Cluster
|
25
|
+
|
26
|
+
Allows to programatically start and stop an Elasticsearch cluster suitable for isolating tests.
|
27
|
+
|
28
|
+
HTTP service is running on ports `9250-*` by default, and the cluster runs in-memory only.
|
29
|
+
|
30
|
+
Start and stop the default cluster:
|
31
|
+
|
32
|
+
require 'elasticsearch/extensions/test/cluster'
|
33
|
+
|
34
|
+
Elasticsearch::Extensions::Test::Cluster.start
|
35
|
+
Elasticsearch::Extensions::Test::Cluster.stop
|
36
|
+
|
37
|
+
Start the cluster on specific port, with a specific Elasticsearch version, number of nodes and cluster name:
|
38
|
+
|
39
|
+
require 'elasticsearch/extensions/test/cluster'
|
40
|
+
|
41
|
+
Elasticsearch::Extensions::Test::Cluster.start \
|
42
|
+
cluster_name: "my-testing-cluster",
|
43
|
+
command: "/usr/local/Cellar/elasticsearch/1.0.0.Beta2/bin/elasticsearch",
|
44
|
+
nodes: 3,
|
45
|
+
port: 9350
|
46
|
+
|
47
|
+
# Starting 3 Elasticsearch nodes.....................
|
48
|
+
# --------------------------------------------------------------------------------
|
49
|
+
# Cluster: my-testing-cluster
|
50
|
+
# Status: green
|
51
|
+
# Nodes: 3
|
52
|
+
# - node-1 | version: 1.0.0.Beta2, pid: 54469
|
53
|
+
# + node-2 | version: 1.0.0.Beta2, pid: 54470
|
54
|
+
# - node-3 | version: 1.0.0.Beta2, pid: 54468
|
55
|
+
# => true
|
56
|
+
|
57
|
+
|
58
|
+
Stop this cluster:
|
59
|
+
|
60
|
+
require 'elasticsearch/extensions/test/cluster'
|
61
|
+
|
62
|
+
Elasticsearch::Extensions::Test::Cluster.stop \
|
63
|
+
command: "/usr/local/Cellar/elasticsearch/1.0.0.Beta2/bin/elasticsearch",
|
64
|
+
port: 9350
|
65
|
+
|
66
|
+
# Stopping Elasticsearch nodes... stopped PID 54469. stopped PID 54470. stopped PID 54468.
|
67
|
+
# # => [54469, 54470, 54468]
|
68
|
+
|
69
|
+
[Full documentation](http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/Test/Cluster)
|
70
|
+
|
71
|
+
### Test::StartupShutdown
|
72
|
+
|
73
|
+
Allows to register `startup` and `shutdown` hooks for Test::Unit, similarly to RSpec's `before(:all)`,
|
74
|
+
compatible with the [Test::Unit 2](https://github.com/test-unit/test-unit/blob/master/lib/test/unit/testcase.rb) syntax.
|
75
|
+
|
76
|
+
The extension is useful for e.g. starting the testing Elasticsearch cluster before the test suite is executed,
|
77
|
+
and stopping it afterwards.
|
78
|
+
|
79
|
+
** IMPORTANT NOTE ** You have to register the handler for `shutdown` hook before requiring 'test/unit':
|
80
|
+
|
81
|
+
# File: test_helper.rb
|
82
|
+
at_exit { MyTest.__run_at_exit_hooks }
|
83
|
+
require 'test/unit'
|
84
|
+
|
85
|
+
Example of handler registration:
|
86
|
+
|
87
|
+
class MyTest < Test::Unit::TestCase
|
88
|
+
extend Elasticsearch::Extensions::Test::StartupShutdown
|
89
|
+
|
90
|
+
startup { puts "Suite starting up..." }
|
91
|
+
shutdown { puts "Suite shutting down..." }
|
92
|
+
end
|
93
|
+
|
94
|
+
[Full documentation](http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/Test/StartupShutdown)
|
95
|
+
|
96
|
+
Examples in the Elasticsearch gem test suite: [1](https://github.com/elasticsearch/elasticsearch-ruby/blob/master/elasticsearch-transport/test/integration/client_test.rb#L4-L6), [2](https://github.com/elasticsearch/elasticsearch-ruby/blob/master/elasticsearch-transport/test/test_helper.rb#L44)
|
97
|
+
|
98
|
+
### Test::Profiling
|
99
|
+
|
100
|
+
Allows to define and execute profiling tests within [Shoulda](https://github.com/thoughtbot/shoulda) contexts.
|
101
|
+
Measures operations and reports statistics, including code profile.
|
102
|
+
|
103
|
+
Let's define a simple profiling test in a `profiling_test.rb` file:
|
104
|
+
|
105
|
+
require 'test/unit'
|
106
|
+
require 'shoulda/context'
|
107
|
+
require 'elasticsearch/extensions/test/profiling'
|
108
|
+
|
109
|
+
class ProfilingTest < Test::Unit::TestCase
|
110
|
+
extend Elasticsearch::Extensions::Test::Profiling
|
111
|
+
|
112
|
+
context "Mathematics" do
|
113
|
+
measure "divide numbers", count: 10_000 do
|
114
|
+
assert_nothing_raised { 1/2 }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
Let's run it:
|
121
|
+
|
122
|
+
$ QUIET=y ruby profiling_test.rb
|
123
|
+
|
124
|
+
...
|
125
|
+
ProfilingTest
|
126
|
+
|
127
|
+
-------------------------------------------------------------------------------
|
128
|
+
Context: Mathematics should divide numbers (10000x)
|
129
|
+
mean: 0.03ms | avg: 0.03ms | max: 0.14ms
|
130
|
+
-------------------------------------------------------------------------------
|
131
|
+
PASS (0:00:00.490) test: Mathematics should divide numbers (10000x).
|
132
|
+
...
|
133
|
+
|
134
|
+
When using the `QUIET` option, only the statistics on operation throughput are printed.
|
135
|
+
When omitted, the full code profile by [RubyProf](https://github.com/ruby-prof/ruby-prof) is printed.
|
136
|
+
|
137
|
+
[Full documentation](http://rubydoc.info/gems/elasticsearch-extensions/Elasticsearch/Extensions/Test/StartupShutdown)
|
138
|
+
|
139
|
+
[Example in the Elasticsearch gem](https://github.com/elasticsearch/elasticsearch-ruby/blob/master/elasticsearch-transport/test/profile/client_benchmark_test.rb)
|
140
|
+
|
23
141
|
|
24
142
|
## Installation
|
25
143
|
|
data/Rakefile
CHANGED
@@ -49,17 +49,15 @@ namespace :test do
|
|
49
49
|
desc "Start Elasticsearch nodes for tests"
|
50
50
|
task :start do
|
51
51
|
$LOAD_PATH << File.expand_path('../lib', __FILE__) << File.expand_path('../test', __FILE__)
|
52
|
-
require 'elasticsearch/
|
53
|
-
|
54
|
-
Elasticsearch::TestCluster.start
|
52
|
+
require 'elasticsearch/extensions/test/cluster'
|
53
|
+
Elasticsearch::Extensions::Test::Cluster.start
|
55
54
|
end
|
56
55
|
|
57
56
|
desc "Stop Elasticsearch nodes for tests"
|
58
57
|
task :stop do
|
59
58
|
$LOAD_PATH << File.expand_path('../lib', __FILE__) << File.expand_path('../test', __FILE__)
|
60
|
-
require 'elasticsearch/
|
61
|
-
|
62
|
-
Elasticsearch::TestCluster.stop
|
59
|
+
require 'elasticsearch/extensions/test/cluster'
|
60
|
+
Elasticsearch::Extensions::Test::Cluster.stop
|
63
61
|
end
|
64
62
|
end
|
65
63
|
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'json'
|
5
|
+
require 'ansi'
|
6
|
+
|
7
|
+
STDOUT.sync = true
|
8
|
+
|
9
|
+
class String
|
10
|
+
|
11
|
+
# Redefine the ANSI method: do not print ANSI when not running in the terminal
|
12
|
+
#
|
13
|
+
def ansi(*args)
|
14
|
+
STDOUT.tty? ? ANSI.ansi(self, *args) : self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Elasticsearch
|
19
|
+
module Extensions
|
20
|
+
module Test
|
21
|
+
|
22
|
+
# A convenience Ruby class for starting and stopping a separate testing in-memory cluster,
|
23
|
+
# to not depend on -- and not mess up -- <localhost:9200>.
|
24
|
+
#
|
25
|
+
# @example Start a cluster with default configuration
|
26
|
+
# require 'elasticsearch/extensions/test/cluster'
|
27
|
+
# Elasticsearch::Extensions::Test::Cluster.start
|
28
|
+
#
|
29
|
+
# @see Cluster#start Cluster.start
|
30
|
+
# @see Cluster#stop Cluster.stop
|
31
|
+
#
|
32
|
+
module Cluster
|
33
|
+
|
34
|
+
# Starts a cluster
|
35
|
+
#
|
36
|
+
# Launches the specified number of nodes in test-suitable configuration by default
|
37
|
+
# and prints information about the cluster -- unless this specific cluster is running already.
|
38
|
+
#
|
39
|
+
# Use the {Cluster#stop Cluster.stop} command with the same arguments to stop this cluster.
|
40
|
+
#
|
41
|
+
# @option arguments [String] :command Elasticsearch command (default: `elasticsearch`).
|
42
|
+
# @option arguments [Integer] :nodes Number of desired nodes (default: 2).
|
43
|
+
# @option arguments [String] :cluster_name Cluster name (default: `elasticsearch_test`).
|
44
|
+
# @option arguments [String] :port Starting port number; will be auto-incremented (default: 9250).
|
45
|
+
# @option arguments [Integer] :timeout Timeout when starting the cluster (default: 30).
|
46
|
+
#
|
47
|
+
# You can also use environment variables to set these options.
|
48
|
+
#
|
49
|
+
# @example Start a cluster with default configuration (2 nodes, in-memory, etc)
|
50
|
+
# Elasticsearch::Extensions::Test::Cluster.start
|
51
|
+
#
|
52
|
+
# @example Start a cluster with a custom configuration
|
53
|
+
# Elasticsearch::Extensions::Test::Cluster.start \
|
54
|
+
# cluster_name: 'my-cluster',
|
55
|
+
# nodes: 3,
|
56
|
+
# node_name: 'my-node',
|
57
|
+
# port: 9350
|
58
|
+
#
|
59
|
+
# @example Start a cluster with a different Elasticsearch version
|
60
|
+
# Elasticsearch::Extensions::Test::Cluster.start \
|
61
|
+
# command: "/usr/local/Cellar/elasticsearch/1.0.0.Beta2/bin/elasticsearch"
|
62
|
+
#
|
63
|
+
# @return Boolean
|
64
|
+
# @see Cluster#stop Cluster.stop
|
65
|
+
#
|
66
|
+
def start(arguments={})
|
67
|
+
@@number_of_nodes = (ENV['TEST_CLUSTER_NODES'] || arguments[:nodes] || 2).to_i
|
68
|
+
|
69
|
+
arguments[:command] ||= ENV['TEST_CLUSTER_COMMAND'] || 'elasticsearch'
|
70
|
+
arguments[:port] ||= (ENV['TEST_CLUSTER_PORT'] || 9250).to_i
|
71
|
+
arguments[:cluster_name] ||= ENV['TEST_CLUSTER_NAME'] || 'elasticsearch_test'
|
72
|
+
arguments[:node_name] ||= 'node'
|
73
|
+
arguments[:timeout] ||= 30
|
74
|
+
|
75
|
+
if running? :on => arguments[:port], :as => arguments[:cluster_name]
|
76
|
+
print "[!] Elasticsearch cluster already running".ansi(:red)
|
77
|
+
wait_for_green(arguments[:port], arguments[:timeout])
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
|
81
|
+
print "Starting ".ansi(:faint) +
|
82
|
+
@@number_of_nodes.to_s.ansi(:bold, :faint) +
|
83
|
+
" Elasticsearch nodes..".ansi(:faint)
|
84
|
+
|
85
|
+
@@number_of_nodes.times do |n|
|
86
|
+
n += 1
|
87
|
+
pidfile = File.expand_path("tmp/elasticsearch-#{n}.pid", Dir.pwd)
|
88
|
+
pid = Process.spawn <<-COMMAND
|
89
|
+
#{arguments[:command]} \
|
90
|
+
-D es.foreground=yes \
|
91
|
+
-D es.cluster.name=#{arguments[:cluster_name]} \
|
92
|
+
-D es.node.name=#{arguments[:node_name]}-#{n} \
|
93
|
+
-D es.http.port=#{arguments[:port].to_i + (n-1)} \
|
94
|
+
-D es.gateway.type=none \
|
95
|
+
-D es.index.store.type=memory \
|
96
|
+
-D es.network.host=0.0.0.0 \
|
97
|
+
-D es.discovery.zen.ping.multicast.enabled=true \
|
98
|
+
-D es.pidfile=#{pidfile} \
|
99
|
+
> /dev/null 2>&1
|
100
|
+
COMMAND
|
101
|
+
Process.detach pid
|
102
|
+
end
|
103
|
+
|
104
|
+
wait_for_green(arguments[:port], arguments[:timeout])
|
105
|
+
return true
|
106
|
+
end
|
107
|
+
|
108
|
+
# Stop the cluster.
|
109
|
+
#
|
110
|
+
# Fetches the PID numbers from "Nodes Info" API and terminates matching nodes.
|
111
|
+
#
|
112
|
+
# @example Stop the default cluster
|
113
|
+
# Elasticsearch::Extensions::Test::Cluster.stop
|
114
|
+
#
|
115
|
+
# @example Stop the cluster reachable on specific port
|
116
|
+
# Elasticsearch::Extensions::Test::Cluster.stop port: 9350
|
117
|
+
#
|
118
|
+
# @return Boolean
|
119
|
+
# @see Cluster#start Cluster.start
|
120
|
+
#
|
121
|
+
def stop(arguments={})
|
122
|
+
arguments[:port] ||= (ENV['TEST_CLUSTER_PORT'] || 9250).to_i
|
123
|
+
|
124
|
+
nodes = JSON.parse(Net::HTTP.get(URI("http://localhost:#{arguments[:port]}/_cluster/nodes/?process"))) rescue nil
|
125
|
+
|
126
|
+
return false if nodes.nil? or nodes.empty?
|
127
|
+
|
128
|
+
pids = nodes['nodes'].map { |id, info| info['process']['id'] }
|
129
|
+
|
130
|
+
unless pids.empty?
|
131
|
+
print "Stopping Elasticsearch nodes... ".ansi(:faint)
|
132
|
+
pids.each_with_index do |pid, i|
|
133
|
+
begin
|
134
|
+
print "stopped PID #{pid}. ".ansi(:green) if Process.kill 'KILL', pid
|
135
|
+
rescue Exception => e
|
136
|
+
print "[#{e.class}] PID #{pid} not found. ".ansi(:red)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
puts
|
140
|
+
else
|
141
|
+
false
|
142
|
+
end
|
143
|
+
|
144
|
+
return pids
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns true when a specific test node is running within the cluster.
|
148
|
+
#
|
149
|
+
# @option arguments [Integer] :on The port on which the node is running.
|
150
|
+
# @option arguments [String] :as The cluster name.
|
151
|
+
#
|
152
|
+
# @return Boolean
|
153
|
+
#
|
154
|
+
def running?(arguments={})
|
155
|
+
port = arguments[:on] || (ENV['TEST_CLUSTER_PORT'] || 9250).to_i
|
156
|
+
cluster_name = arguments[:as] || ENV['TEST_CLUSTER_NAME'] || 'elasticsearch_test'
|
157
|
+
|
158
|
+
if cluster_health = Timeout::timeout(0.25) { __get_cluster_health(port) } rescue nil
|
159
|
+
return cluster_health['cluster_name'] == cluster_name && \
|
160
|
+
cluster_health['number_of_nodes'] == @@number_of_nodes
|
161
|
+
end
|
162
|
+
return false
|
163
|
+
end
|
164
|
+
|
165
|
+
# Waits until the cluster is green and prints information
|
166
|
+
#
|
167
|
+
# @example Print the information about the default cluster
|
168
|
+
# Elasticsearch::Extensions::Test::Cluster.wait_for_green
|
169
|
+
#
|
170
|
+
# @param (see #__wait_for_status)
|
171
|
+
#
|
172
|
+
# @return Boolean
|
173
|
+
#
|
174
|
+
def wait_for_green(port=9250, timeout=60)
|
175
|
+
__wait_for_status('green', port, timeout)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Blocks the process and waits for the cluster to be in a "green" state.
|
179
|
+
#
|
180
|
+
# Prints information about the cluster on STDOUT if the cluster is available.
|
181
|
+
#
|
182
|
+
# @param status [String] The status to wait for (yellow, green)
|
183
|
+
# @param port [Integer] The port on which the cluster is reachable
|
184
|
+
# @param timeout [Integer] The explicit timeout for the operation
|
185
|
+
#
|
186
|
+
# @api private
|
187
|
+
#
|
188
|
+
# @return Boolean
|
189
|
+
#
|
190
|
+
def __wait_for_status(status='green', port=9250, timeout=30)
|
191
|
+
uri = URI("http://localhost:#{port}/_cluster/health?wait_for_status=#{status}")
|
192
|
+
|
193
|
+
Timeout::timeout(timeout) do
|
194
|
+
loop do
|
195
|
+
response = begin
|
196
|
+
JSON.parse(Net::HTTP.get(uri))
|
197
|
+
rescue Exception => e
|
198
|
+
puts e.inspect if ENV['DEBUG']
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
|
202
|
+
if response && response['status'] == status && ( @@number_of_nodes.nil? || @@number_of_nodes == response['number_of_nodes'].to_i )
|
203
|
+
__print_cluster_info(port) and break
|
204
|
+
end
|
205
|
+
|
206
|
+
print '.'.ansi(:faint)
|
207
|
+
sleep 1
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
return true
|
212
|
+
end
|
213
|
+
|
214
|
+
# Print information about the cluster on STDOUT
|
215
|
+
#
|
216
|
+
# @api private
|
217
|
+
#
|
218
|
+
def __print_cluster_info(port)
|
219
|
+
health = JSON.parse(Net::HTTP.get(URI("http://localhost:#{port}/_cluster/health")))
|
220
|
+
nodes = JSON.parse(Net::HTTP.get(URI("http://localhost:#{port}/_cluster/nodes/?process")))
|
221
|
+
master = JSON.parse(Net::HTTP.get(URI("http://localhost:#{port}/_cluster/state")))['master_node']
|
222
|
+
|
223
|
+
puts "\n",
|
224
|
+
('-'*80).ansi(:faint),
|
225
|
+
'Cluster: '.ljust(20).ansi(:faint) + health['cluster_name'].to_s.ansi(:faint),
|
226
|
+
'Status: '.ljust(20).ansi(:faint) + health['status'].to_s.ansi(:faint),
|
227
|
+
'Nodes: '.ljust(20).ansi(:faint) + health['number_of_nodes'].to_s.ansi(:faint)
|
228
|
+
|
229
|
+
nodes['nodes'].each do |id, info|
|
230
|
+
m = id == master ? '+' : '-'
|
231
|
+
puts ''.ljust(20) +
|
232
|
+
"#{m} #{info['name'].ansi(:bold)} | version: #{info['version']}, pid: #{info['process']['id']}".ansi(:faint)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Tries to load cluster health information
|
237
|
+
#
|
238
|
+
# @api private
|
239
|
+
#
|
240
|
+
def __get_cluster_health(port=9250)
|
241
|
+
uri = URI("http://localhost:#{port}/_cluster/health")
|
242
|
+
if response = Net::HTTP.get(uri) rescue nil
|
243
|
+
return JSON.parse(response)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
extend self
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'ruby-prof'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'ansi'
|
4
|
+
|
5
|
+
module Elasticsearch
|
6
|
+
module Extensions
|
7
|
+
module Test
|
8
|
+
|
9
|
+
# Allows to define and execute profiling tests within [Shoulda](https://github.com/thoughtbot/shoulda) contexts.
|
10
|
+
#
|
11
|
+
# Measures operations and reports statistics, including code profile.
|
12
|
+
#
|
13
|
+
# Uses the "benchmark" standard library and the "ruby-prof" gem.
|
14
|
+
#
|
15
|
+
# File: profiling_test.rb
|
16
|
+
#
|
17
|
+
# require 'test/unit'
|
18
|
+
# require 'shoulda/context'
|
19
|
+
# require 'elasticsearch/extensions/test/profiling'
|
20
|
+
#
|
21
|
+
# class ProfilingTest < Test::Unit::TestCase
|
22
|
+
# extend Elasticsearch::Extensions::Test::Profiling
|
23
|
+
#
|
24
|
+
# context "Mathematics" do
|
25
|
+
# measure "divide numbers", count: 10_000 do
|
26
|
+
# assert_nothing_raised { 1/2 }
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# $ QUIET=y ruby profiling_test.rb
|
33
|
+
#
|
34
|
+
# ...
|
35
|
+
# ProfilingTest
|
36
|
+
#
|
37
|
+
# -------------------------------------------------------------------------------
|
38
|
+
# Context: Mathematics should divide numbers (10000x)
|
39
|
+
# mean: 0.03ms | avg: 0.03ms | max: 0.14ms
|
40
|
+
# -------------------------------------------------------------------------------
|
41
|
+
# PASS (0:00:00.490) test: Mathematics should divide numbers (10000x).
|
42
|
+
# ...
|
43
|
+
#
|
44
|
+
module Profiling
|
45
|
+
|
46
|
+
# Profiles the passed block of code.
|
47
|
+
#
|
48
|
+
# measure "divide numbers", count: 10_000 do
|
49
|
+
# assert_nothing_raised { 1/2 }
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# @todo Try to make progress bar not to interfere with tests
|
53
|
+
#
|
54
|
+
def measure(name, options={}, &block)
|
55
|
+
___ = '-'*ANSI::Terminal.terminal_width
|
56
|
+
test_name = self.name.split('::').last
|
57
|
+
context_name = self.context(nil) {}.first.parent.name
|
58
|
+
count = Integer(ENV['COUNT'] || options[:count] || 1_000)
|
59
|
+
ticks = []
|
60
|
+
# progress = ANSI::Progressbar.new("#{name} (#{count}x)", count)
|
61
|
+
|
62
|
+
should "#{name} (#{count}x)" do
|
63
|
+
RubyProf.start
|
64
|
+
|
65
|
+
count.times do
|
66
|
+
ticks << Benchmark.realtime { self.instance_eval(&block) }
|
67
|
+
# RubyProf.pause
|
68
|
+
# progress.inc
|
69
|
+
# RubyProf.resume
|
70
|
+
end
|
71
|
+
|
72
|
+
result = RubyProf.stop
|
73
|
+
# progress.finish
|
74
|
+
|
75
|
+
total = result.threads.reduce(0) { |total,info| total += info.total_time; total }
|
76
|
+
mean = (ticks.sort[(ticks.size/2).round-1])*1000
|
77
|
+
avg = (ticks.inject {|sum,el| sum += el; sum}.to_f/ticks.size)*1000
|
78
|
+
max = ticks.max*1000
|
79
|
+
|
80
|
+
|
81
|
+
result.eliminate_methods!([/Integer#times|Benchmark.realtime|ANSI::Code#.*|ANSI::ProgressBar#.*/])
|
82
|
+
printer = RubyProf::FlatPrinter.new(result)
|
83
|
+
# printer = RubyProf::GraphPrinter.new(result)
|
84
|
+
|
85
|
+
puts "\n",
|
86
|
+
___,
|
87
|
+
'Context: ' + ANSI.bold(context_name) + ' should ' + ANSI.bold(name) + " (#{count}x)",
|
88
|
+
"mean: #{sprintf('%.2f', mean)}ms | " +
|
89
|
+
"avg: #{sprintf('%.2f', avg)}ms | " +
|
90
|
+
"max: #{sprintf('%.2f', max)}ms",
|
91
|
+
___
|
92
|
+
printer.print(STDOUT, {}) unless ENV['QUIET'] || options[:quiet]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Extensions
|
3
|
+
module Test
|
4
|
+
# Startup/shutdown support for test suites
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
#
|
8
|
+
# class MyTest < Test::Unit::TestCase
|
9
|
+
# extend Elasticsearch::Extensions::Test::StartupShutdown
|
10
|
+
#
|
11
|
+
# startup { puts "Suite starting up..." }
|
12
|
+
# shutdown { puts "Suite shutting down..." }
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# *** IMPORTANT NOTE: **********************************************************
|
16
|
+
#
|
17
|
+
# You have to register the handler for shutdown before requiring 'test/unit':
|
18
|
+
#
|
19
|
+
# # File: test_helper.rb
|
20
|
+
# at_exit { MyTest.__run_at_exit_hooks }
|
21
|
+
# require 'test/unit'
|
22
|
+
#
|
23
|
+
# The API follows Test::Unit 2.0
|
24
|
+
# <https://github.com/test-unit/test-unit/blob/master/lib/test/unit/testcase.rb>
|
25
|
+
#
|
26
|
+
module StartupShutdown
|
27
|
+
@@started = false
|
28
|
+
@@shutdown_blocks ||= []
|
29
|
+
|
30
|
+
def startup &block
|
31
|
+
return if started?
|
32
|
+
@@started = true
|
33
|
+
yield block if block_given?
|
34
|
+
end
|
35
|
+
|
36
|
+
def shutdown &block
|
37
|
+
@@shutdown_blocks << block if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
def started?
|
41
|
+
!! @@started
|
42
|
+
end
|
43
|
+
|
44
|
+
def __run_at_exit_hooks
|
45
|
+
return unless started?
|
46
|
+
STDERR.puts ANSI.faint("Running at_exit hooks...")
|
47
|
+
puts ANSI.faint('-'*80)
|
48
|
+
@@shutdown_blocks.each { |b| b.call }
|
49
|
+
puts ANSI.faint('-'*80)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: elasticsearch
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: ruby-prof
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: bundler
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -238,6 +254,9 @@ files:
|
|
238
254
|
- lib/elasticsearch/extensions/ansi/actions.rb
|
239
255
|
- lib/elasticsearch/extensions/ansi/helpers.rb
|
240
256
|
- lib/elasticsearch/extensions/ansi/response.rb
|
257
|
+
- lib/elasticsearch/extensions/test/cluster.rb
|
258
|
+
- lib/elasticsearch/extensions/test/profiling.rb
|
259
|
+
- lib/elasticsearch/extensions/test/startup_shutdown.rb
|
241
260
|
- lib/elasticsearch/extensions/version.rb
|
242
261
|
- test/ansi/unit/ansi_test.rb
|
243
262
|
- test/test_helper.rb
|