tlb-core 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +46 -0
- data/core/lib/tasks/tlb.rake +13 -0
- data/core/lib/tlb.rb +243 -0
- data/core/lib/tlb/run_data.rb +55 -0
- data/core/lib/tlb/util.rb +15 -0
- data/core/tlb-alien-0.3.2.jar +0 -0
- metadata +94 -0
data/README.markdown
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
## Using tlb.rb:
|
2
|
+
|
3
|
+
__tlb.rb__ uses [tlb](https://github.com/test-load-balancer/tlb "TLB") under the hood. It runs a sub-process which talks to the actual tlb-server(or equivallent) to balance and post run-feedback.
|
4
|
+
Balancer process is actually an HTTP server which listen to a certain TCP port so tlb-ruby library can talk to it.
|
5
|
+
This is controlled by an environment variable named *'TLB_BALANCER_PORT'*, which can be set to any port number(integer between 1024 to 65535) that is guaranteed to remain un-bound while the build runs.
|
6
|
+
|
7
|
+
In addition to this extra environment variable, the usual TLB environment variable setup is required(so the balancer knows things like what partitioning algorithm to use or the type of server it has to talk to etc).
|
8
|
+
Detailed documentation of TLB environment variable configuration is available at [http://test-load-balancer.github.com](http://test-load-balancer.github.com "Tlb Documentation")
|
9
|
+
|
10
|
+
__tlb.rb__ supports RSpec(1.x and 2.x), Cucumber and Test::Unit, which are the most widely used testing frameworks in the Ruby world.
|
11
|
+
|
12
|
+
__tlb.rb__ is fully compatible with both Ruby 1.9 and 1.8 across __MRI__ and __JRuby__. However, 1.9 support will be available only version 0.3.2 onwards.
|
13
|
+
|
14
|
+
We test __tlb.rb__ on MRI and JRuby, however it should work with other flavours of Ruby(like REE) as well.
|
15
|
+
|
16
|
+
## Getting tlb.rb:
|
17
|
+
|
18
|
+
__RSpec2__ support(both __1.9__ and __1.8__):
|
19
|
+
$ gem install tlb-rspec2
|
20
|
+
|
21
|
+
__Cucumber__ support(both __1.9__ and __1.8__):
|
22
|
+
$ gem install tlb-cucumber
|
23
|
+
|
24
|
+
__RSpec1__ support(both __1.9__ and __1.8__):
|
25
|
+
$ gem install tlb-rspec1
|
26
|
+
|
27
|
+
__Test::Unit__ support on Ruby __1.9__:(available 0.3.2 onwards)
|
28
|
+
$ gem install tlb-testunit19
|
29
|
+
|
30
|
+
__Test::Unit__ support on Ruby __1.8__:(available 0.3.2 onwards)
|
31
|
+
$ gem install tlb-testunit18
|
32
|
+
|
33
|
+
If a version older than 0.3.2, please use
|
34
|
+
$ gem install tlb-testunit
|
35
|
+
for Test::Unit support.
|
36
|
+
|
37
|
+
## Setting it up for your project
|
38
|
+
|
39
|
+
Please refer documentation on [http://test-load-balancer.github.com/](http://test-load-balancer.github.com/ "TLB Website") for detailed setup instructions.
|
40
|
+
|
41
|
+
Documentation also explains TLB concepts and customization options in fair amount of detail. We highly recomend going through the TLB documentation.
|
42
|
+
|
43
|
+
## Want a feature? Found a bug?
|
44
|
+
|
45
|
+
Post it at [Issue Tracker](http://code.google.com/p/tlb/issues/list "Issue Tracker").
|
46
|
+
|
data/core/lib/tlb.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'open4'
|
3
|
+
require 'net/http'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module Tlb
|
7
|
+
TLB_OUT_FILE = 'TLB_OUT_FILE'
|
8
|
+
TLB_ERR_FILE = 'TLB_ERR_FILE'
|
9
|
+
TLB_APP = 'TLB_APP'
|
10
|
+
DEFAULT_TLB_BALANCER_STARTUP_TIME = '120'
|
11
|
+
|
12
|
+
module Balancer
|
13
|
+
TLB_BALANCER_PORT = 'TLB_BALANCER_PORT'
|
14
|
+
BALANCE_PATH = '/balance'
|
15
|
+
SUITE_TIME_REPORTING_PATH = '/suite_time'
|
16
|
+
SUITE_RESULT_REPORTING_PATH = '/suite_result'
|
17
|
+
|
18
|
+
def self.host
|
19
|
+
'localhost'
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.port
|
23
|
+
ENV[TLB_BALANCER_PORT] || '8019'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.send path, data
|
27
|
+
Net::HTTP.start(host, port) do |h|
|
28
|
+
res = h.post(path, data)
|
29
|
+
res.value
|
30
|
+
res.body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.get path
|
35
|
+
Net::HTTP.get_response(host, path, port).body
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.running?
|
39
|
+
get("/control/status") == "RUNNING"
|
40
|
+
rescue
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.terminate
|
45
|
+
get("/control/suicide")
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.wait_for_start
|
49
|
+
loop do
|
50
|
+
begin
|
51
|
+
break if running?
|
52
|
+
rescue
|
53
|
+
#ignore
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module RSpec
|
60
|
+
end
|
61
|
+
|
62
|
+
module TestUnit
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.relative_file_path file_name
|
66
|
+
abs_file_name = File.expand_path(file_name)
|
67
|
+
rel_file_name = abs_file_name.sub(/^#{Dir.pwd}/, '.')
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.relative_file_paths file_names
|
71
|
+
file_names.map { |file_name| relative_file_path(file_name) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.balance_and_order file_set
|
75
|
+
ensure_server_running
|
76
|
+
Balancer.send(Balancer::BALANCE_PATH, file_set.join("\n")).split("\n")
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.suite_result suite_name, result
|
80
|
+
ensure_server_running
|
81
|
+
Balancer.send(Balancer::SUITE_RESULT_REPORTING_PATH, "#{suite_name}: #{result}")
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.suite_time suite_name, mills
|
85
|
+
ensure_server_running
|
86
|
+
Balancer.send(Balancer::SUITE_TIME_REPORTING_PATH, "#{suite_name}: #{mills}")
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.fail_as_balancer_is_not_running
|
90
|
+
raise "Balancer server must be started before tests are run."
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.ensure_server_running
|
94
|
+
server_running? || fail_as_balancer_is_not_running
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.server_running?
|
98
|
+
Balancer.running?
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.root_dir
|
102
|
+
File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.tlb_jar
|
106
|
+
File.expand_path(Dir.glob(File.join(root_dir, "tlb-alien*")).first)
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.server_command
|
110
|
+
"java -jar #{tlb_jar}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.can_fork?
|
114
|
+
RUBY_PLATFORM != 'java'
|
115
|
+
end
|
116
|
+
|
117
|
+
class BalancerProcess
|
118
|
+
class StreamPumper
|
119
|
+
def initialize stream, file
|
120
|
+
@stream, @file = stream, file
|
121
|
+
@thd = Thread.new { pump }
|
122
|
+
end
|
123
|
+
|
124
|
+
def pump
|
125
|
+
loop do
|
126
|
+
data_available? && flush_stream
|
127
|
+
Thread.current[:stop_pumping] && break
|
128
|
+
sleep 0.1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def flush_stream
|
133
|
+
File.open(ENV[@file], 'a') do |h|
|
134
|
+
h.write(read)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def stop_pumping!
|
139
|
+
@thd[:stop_pumping] = true
|
140
|
+
@thd.join
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def initialize server_command
|
145
|
+
pumper_type, out, err = start(server_command)
|
146
|
+
@out_pumper = pumper_type.new(out, TLB_OUT_FILE)
|
147
|
+
@err_pumper = pumper_type.new(err, TLB_ERR_FILE)
|
148
|
+
end
|
149
|
+
|
150
|
+
def stop_pumping
|
151
|
+
@out_pumper.stop_pumping!
|
152
|
+
@err_pumper.stop_pumping!
|
153
|
+
end
|
154
|
+
|
155
|
+
def die
|
156
|
+
Balancer.terminate
|
157
|
+
stop_pumping
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class ForkBalancerProcess < BalancerProcess
|
162
|
+
def start server_command
|
163
|
+
@pid, input, out, err = Open4.popen4(server_command)
|
164
|
+
unless (out)
|
165
|
+
raise "out was nil"
|
166
|
+
end
|
167
|
+
return Class.new(StreamPumper) do
|
168
|
+
def data_available?
|
169
|
+
not @stream.eof?
|
170
|
+
end
|
171
|
+
|
172
|
+
def read
|
173
|
+
@stream.read
|
174
|
+
end
|
175
|
+
end, out, err
|
176
|
+
end
|
177
|
+
|
178
|
+
def die
|
179
|
+
super
|
180
|
+
@pid = nil
|
181
|
+
Process.wait
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class JavaBalancerProcess < BalancerProcess
|
186
|
+
def start server_command
|
187
|
+
require 'java'
|
188
|
+
pb = java.lang.ProcessBuilder.new(server_command.split)
|
189
|
+
ENV.each do |key, val|
|
190
|
+
pb.environment[key] = val
|
191
|
+
end
|
192
|
+
@process = pb.start()
|
193
|
+
return Class.new(StreamPumper) do
|
194
|
+
def data_available?
|
195
|
+
@stream.ready
|
196
|
+
end
|
197
|
+
|
198
|
+
def read
|
199
|
+
@stream.read_line
|
200
|
+
end
|
201
|
+
|
202
|
+
def stop_pumping!
|
203
|
+
super
|
204
|
+
@stream.close
|
205
|
+
end
|
206
|
+
end, buf_reader(@process.input_stream), buf_reader(@process.error_stream)
|
207
|
+
end
|
208
|
+
|
209
|
+
def buf_reader stream
|
210
|
+
java.io.BufferedReader.new(java.io.InputStreamReader.new(stream))
|
211
|
+
end
|
212
|
+
|
213
|
+
def die
|
214
|
+
super
|
215
|
+
@process.destroy
|
216
|
+
@process.waitFor
|
217
|
+
@process = nil
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.balancer_process_type
|
222
|
+
can_fork? ? ForkBalancerProcess : JavaBalancerProcess
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.max_startup_time
|
226
|
+
(ENV['TLB_BALANCER_STARTUP_MAXTIME'] || DEFAULT_TLB_BALANCER_STARTUP_TIME).to_i
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.start_server
|
230
|
+
Timeout::timeout(max_startup_time) do
|
231
|
+
ENV[TLB_APP] = 'tlb.balancer.BalancerInitializer'
|
232
|
+
bal_klass = balancer_process_type
|
233
|
+
@balancer_process = bal_klass.new(server_command)
|
234
|
+
Balancer.wait_for_start
|
235
|
+
end
|
236
|
+
rescue Timeout::Error => e
|
237
|
+
raise "TLB server failed to start in 2 seconds. This usually happens when TLB configuration(environment variables) is incorrect. Please check your environment variable configuration."
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.stop_server
|
241
|
+
@balancer_process.die
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'tlb'
|
2
|
+
|
3
|
+
module Tlb::RunData
|
4
|
+
class Suite < Struct.new(:identity, :start_time, :end_time, :failed)
|
5
|
+
MILLS_PER_SEC = 1000
|
6
|
+
|
7
|
+
def initialize(identity, start_time)
|
8
|
+
super(identity, start_time, start_time, false)
|
9
|
+
end
|
10
|
+
|
11
|
+
def run_time
|
12
|
+
((end_time - start_time)*MILLS_PER_SEC).to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def for_id? new_identity
|
16
|
+
identity == new_identity
|
17
|
+
end
|
18
|
+
|
19
|
+
def report_to_tlb
|
20
|
+
Tlb.suite_time(identity, run_time)
|
21
|
+
Tlb.suite_result(identity, failed)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def suite_started identity
|
26
|
+
unless (suites.last && suites.last.for_id?(identity))
|
27
|
+
suites << Tlb::RunData::Suite.new(identity, Time.now)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_suite_data identity
|
32
|
+
if (suite = suites.last) #stupid framework :: retarded fix (this is necessary since rspec-1[don't know if rspec-2 is as stupid too] creates example_proxies for every example it runs, as though its an independent spec-group)
|
33
|
+
suite.end_time = Time.now
|
34
|
+
block_given? && yield(suite)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_suite_failed identity
|
39
|
+
update_suite_data(identity) do |suite|
|
40
|
+
suite.failed = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def report_all_suite_data
|
45
|
+
suites.each do |suite_time|
|
46
|
+
suite_time.report_to_tlb
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def suites
|
53
|
+
@suites ||= []
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'tlb'
|
2
|
+
|
3
|
+
module Tlb::Util
|
4
|
+
def self.quote_path *fragments
|
5
|
+
single_quote(File.expand_path(File.join(*fragments)))
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.single_quote str
|
9
|
+
"'#{escape_quote(str)}'"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.escape_quote str
|
13
|
+
str.gsub(/'/, "\\'")
|
14
|
+
end
|
15
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tlb-core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.2
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Janmejay Singh
|
9
|
+
- Pavan KS
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2011-05-27 00:00:00 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rake
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: open4
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.0.1
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
description: |
|
39
|
+
TLB-Ruby base library that provides common test-load-balancing infrastructure for Ruby testing tools. Core in itself is framework agnostic. It exposes APIs that allow any framework specific libraries to load-balance.
|
40
|
+
|
41
|
+
email: singh.janmejay@gmail.com;itspanzi@gmail.com
|
42
|
+
executables: []
|
43
|
+
|
44
|
+
extensions: []
|
45
|
+
|
46
|
+
extra_rdoc_files:
|
47
|
+
- README.markdown
|
48
|
+
files:
|
49
|
+
- core/lib/tasks/tlb.rake
|
50
|
+
- core/lib/tlb.rb
|
51
|
+
- core/lib/tlb/run_data.rb
|
52
|
+
- core/lib/tlb/util.rb
|
53
|
+
- ./core/tlb-alien-0.3.2.jar
|
54
|
+
- README.markdown
|
55
|
+
homepage: http://github.com/test-load-balancer/tlb.rb
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message: |
|
59
|
+
=========================================================================
|
60
|
+
Documentation: Detailed configuration documentation can be found at http://test-load-balancer.github.com. Documentation section in this website hosts documentation for every public release.
|
61
|
+
|
62
|
+
-------------------------------------------------------------------------
|
63
|
+
TLB Setup: You'll need a TLB-Server in your network that is reachable over the network from the machines you use to execute your project's test-suite. Please refer the TLB documentation for details.
|
64
|
+
|
65
|
+
-------------------------------------------------------------------------
|
66
|
+
Note: Core is just the base library that implements common infrastructure for test-load-balancing in Ruby and is completely testing-framework agnostic. It exposes APIs that allow other ruby libraries to load-balance tests. You'll need to install one of the testing-framework specific libraries to make use of it.
|
67
|
+
|
68
|
+
=========================================================================
|
69
|
+
|
70
|
+
rdoc_options:
|
71
|
+
- --charset=UTF-8
|
72
|
+
require_paths:
|
73
|
+
- core/lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
requirements: []
|
87
|
+
|
88
|
+
rubyforge_project: tlb-rb
|
89
|
+
rubygems_version: 1.8.3
|
90
|
+
signing_key:
|
91
|
+
specification_version: 3
|
92
|
+
summary: tlb-core-0.3.2
|
93
|
+
test_files: []
|
94
|
+
|