tlb-testunit 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.emacs_project ADDED
@@ -0,0 +1 @@
1
+ (setq rspec-executable "rspec")
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ TAGS
2
+ tmp
3
+ tlb_store
4
+ tlb-all*.jar
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "tlb"]
2
+ path = tlb
3
+ url = git://github.com/test-load-balancer/tlb.git
data/README.markdown ADDED
@@ -0,0 +1,33 @@
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(java 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 needs to listen to a certain TCP port so that tlb-ruby implementation 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 what server to talk to).
8
+ Detailed documentation of TLB environment variable configuration is available at [https://github.com/test-load-balancer/tlb/wiki/Configuration-Variables](https://github.com/test-load-balancer/tlb/wiki/Configuration-Variables "Tlb config reference")
9
+
10
+ As of now, rspec is the only test framework that tlb_rb supports. We plan to add support for other ruby-testing-frameworks soon.
11
+
12
+ ## Setting it up for your project
13
+
14
+ Please refer the [sample_projects](http://github.com/test-load-balancer/sample_projects "Tlb setup examples") to see the details of how to set it up.
15
+
16
+ Usually, something equivallent of this in one of your Rake files should suffice:
17
+
18
+ PATH_TO_TLB = File.join(RAILS_ROOT, 'vendor', 'plugins', 'tlb_rb', 'lib', 'tlb')
19
+ require PATH_TO_TLB
20
+ require File.join(PATH_TO_TLB, 'spec_task')
21
+
22
+ Tlb::SpecTask.new(:balanced_specs) do |t|
23
+ t.spec_files = FileList['spec/**/*_spec.rb']
24
+ t.spec_opts << "--require #{PATH_TO_TLB},#{File.join(PATH_TO_TLB, 'spec_formatter')} --format 'Tlb::SpecFormatter:/dev/null' --format nested"
25
+ end
26
+
27
+ desc "load balanced spec"
28
+ task :run_balanced => ['tlb:start', :balanced_specs]
29
+
30
+ Where run_balanced is the task you invoke at the top-level(invoked externally).
31
+
32
+ ## RSpec version compatibility
33
+ The branch '__master__' is __RSpec-2.x__ compatible. If you use __RSpec-1__(i.e. __1.3.x__ etc, please use branch named '__rspec-1__'. If you come across any bugs with eiher RSpec-2 or 1 support, please post it as an bug on the issue tracker on github project page.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'rake/testtask'
3
+
4
+ task :test => ['test:rspec', 'test:test_unit']
5
+
6
+ namespace :test do
7
+ RSpec::Core::RakeTask.new(:rspec) do |t|
8
+ t.pattern = 'tests/**/*_spec.rb'
9
+ end
10
+
11
+ Rake::TestTask.new(:test_unit) do |t|
12
+ t.test_files = FileList['tests/**/*_test.rb']
13
+ end
14
+ end
15
+
16
+ task :build_tlb do
17
+ Dir.glob("tlb-all*.jar").each { |jar| FileUtils.rm(jar) }
18
+ sh 'ant -f tlb/build.xml package'
19
+ Dir.glob('tlb/target/tlb-all*').each { |file| FileUtils.copy(file, ".") }
20
+ end
21
+
22
+ task :package do
23
+ `gem build tlb-rspec2.gemspec`
24
+ `gem build tlb-testunit.gemspec`
25
+ end
data/gem_common.rb ADDED
@@ -0,0 +1,56 @@
1
+ BASE_DIR = File.dirname(__FILE__)
2
+ LIB_TLB = File.join(BASE_DIR, "lib", "tlb")
3
+ TEST_DIR = File.join(BASE_DIR, "tests")
4
+ TAG_VERSION = `git describe --abbrev=0`.gsub(/^v/, '')
5
+ CODE_VERSION = `git describe --always`
6
+ AUTHORS = ["Janmejay Singh", "Pavan KS"]
7
+ EMAIL = "singh.janmejay@gmail.com;itspanzi@gmail.com"
8
+ HOME_PAGE = "http://github.com/test-load-balancer/tlb_rb"
9
+ SUMMARY = "#{$name}-#{CODE_VERSION}"
10
+ DESC = <<END
11
+ TLB ruby implementation base, which provides support for load balancing tests written in #{$framework}.
12
+ TLB_rb test suite is not bundled, please check http://github.com/test-load-balancer/tlb_rb for tests.
13
+ Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
14
+ END
15
+ POST_INSTALL_MESSAGE = <<END
16
+ -------------------------------------------------------------------------
17
+ Documentation: Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
18
+ -----------------------------
19
+ Example: https://github.com/test-load-balancer/sample_projects has examples projects and shell script to demonstrate a typical build(by starting a local tlb server, and executing two partitions locally). While partitions in these examples execute one after another, in an actual CI/pre-checkin build, they will actually run parallely on different machines.
20
+ Its a good idea to play with the environment variables values being used in these shell-scripts to understand how they affect TLB's behaviour. You may want to check https://github.com/test-load-balancer/tlb/wiki/Configuration-Variables, which documents each variable and its effect.
21
+ -----------------------------
22
+ Issue tracker: Please report bugs/enhancements/feature-requests at http://code.google.com/p/tlb/issues/list. Github, Rubyforge or any other issue trackers are not monitored or updated.
23
+ -------------------------------------------------------------------------
24
+ END
25
+ RUBYFORGE_PROJECT = "tlb-rb"
26
+ RUBYGEMS_VERSION = "1.3.7"
27
+
28
+ def files *exclude_dirs
29
+ files = `git ls-files`.split("\n")
30
+ files += Dir.glob(File.join(File.dirname(__FILE__), "*.jar")).map { |path| File.basename(path) }
31
+ exclude_dirs.inject(files) { |files, dir| files - `git ls-files #{dir}`.split("\n") }
32
+ end
33
+
34
+
35
+ def configure_tlb s
36
+ s.name = $name
37
+ s.version = TAG_VERSION
38
+ s.platform = Gem::Platform::RUBY
39
+ s.authors = AUTHORS
40
+ s.email = EMAIL
41
+ s.homepage = HOME_PAGE
42
+ s.summary = SUMMARY
43
+ s.description = DESC
44
+
45
+ s.rubyforge_project = RUBYFORGE_PROJECT
46
+ s.rubygems_version = RUBYGEMS_VERSION
47
+
48
+ s.post_install_message = POST_INSTALL_MESSAGE
49
+
50
+ s.extra_rdoc_files = [ "README.markdown" ]
51
+ s.rdoc_options = ["--charset=UTF-8"]
52
+ s.require_path = "lib"
53
+
54
+ s.add_runtime_dependency 'open4', '>= 1.0.1'
55
+ s.add_runtime_dependency 'rake'
56
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'tlb'))
2
+
3
+ namespace :tlb do
4
+ task :start do
5
+ Tlb.start_server
6
+ at_exit do
7
+ $stderr.write "terminating tlb server\n"
8
+ Tlb.stop_server
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,53 @@
1
+ module Tlb::RunData
2
+ class Suite < Struct.new(:identity, :start_time, :end_time, :failed)
3
+ MILLS_PER_SEC = 1000
4
+
5
+ def initialize(identity, start_time)
6
+ super(identity, start_time, start_time, false)
7
+ end
8
+
9
+ def run_time
10
+ ((end_time - start_time)*MILLS_PER_SEC).to_i
11
+ end
12
+
13
+ def for_id? new_identity
14
+ identity == new_identity
15
+ end
16
+
17
+ def report_to_tlb
18
+ Tlb.suite_time(identity, run_time)
19
+ Tlb.suite_result(identity, failed)
20
+ end
21
+ end
22
+
23
+ def suite_started identity
24
+ unless (suites.last && suites.last.for_id?(identity))
25
+ suites << Tlb::RunData::Suite.new(identity, Time.now)
26
+ end
27
+ end
28
+
29
+ def update_suite_data identity
30
+ 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)
31
+ suite.end_time = Time.now
32
+ block_given? && yield(suite)
33
+ end
34
+ end
35
+
36
+ def update_suite_failed identity
37
+ update_suite_data(identity) do |suite|
38
+ suite.failed = true
39
+ end
40
+ end
41
+
42
+ def report_all_suite_data
43
+ suites.each do |suite_time|
44
+ suite_time.report_to_tlb
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def suites
51
+ @suites ||= []
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ require 'tlb/test_unit/test_splitter'
2
+ require 'tlb/test_unit/test_observer'
3
+ require 'test/unit/ui/testrunnermediator'
4
+
5
+ module Tlb::TestUnit::MediatorInflection
6
+ def self.included base
7
+ base.send(:alias_method, :run_suite_without_tlb, :run_suite)
8
+ base.send(:remove_method, :run_suite)
9
+ base.send(:include, InstanceMethods)
10
+
11
+ base.send(:include, Tlb::TestUnit::TestSplitter)
12
+ base.send(:include, Tlb::TestUnit::TestObserver)
13
+ end
14
+
15
+ module InstanceMethods
16
+ def run_suite
17
+ register_observers
18
+ prune_suite
19
+ run_suite_without_tlb
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ Test::Unit::UI::TestRunnerMediator.class_eval do
26
+ include Tlb::TestUnit::MediatorInflection
27
+ end
@@ -0,0 +1,36 @@
1
+ require 'tlb/run_data'
2
+
3
+ module Tlb::TestUnit::TestObserver
4
+ class TestUnitRunData
5
+ include Tlb::RunData
6
+
7
+ def suite_failed(failure)
8
+ update_suite_failed(suite_name_for(failure.test_name))
9
+ end
10
+
11
+ def suite_name_for(test_name)
12
+ test_name.scan(/\((.+)\)$/).flatten.first
13
+ end
14
+ end
15
+
16
+ def register_observers
17
+ run_data = TestUnitRunData.new
18
+
19
+ add_listener(Test::Unit::TestResult::FAULT) do |fault|
20
+ run_data.suite_failed(fault)
21
+ end
22
+
23
+ add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED) do |*elapsed_time|
24
+ run_data.report_all_suite_data
25
+ end
26
+
27
+ add_listener(Test::Unit::TestSuite::STARTED) do |suite_name|
28
+ run_data.suite_started(suite_name)
29
+ end
30
+
31
+
32
+ add_listener(Test::Unit::TestSuite::FINISHED) do |suite_name|
33
+ run_data.update_suite_data(suite_name)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ module Tlb::TestUnit::TestSplitter
2
+ def prune_suite
3
+ name_suite_map = @suite.tests.inject({}) { |map, test| map[test.name] = test; map }
4
+ names_to_run = Tlb.balance_and_order(@suite.tests.map { |test| test.name })
5
+ tests_to_run = names_to_run.inject([]) { |tests, name| tests << name_suite_map[name]; tests }
6
+ @suite.instance_variable_set('@tests', tests_to_run)
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ class Tlb::TestUnit::TestTask < Rake::TestTask
5
+ def initialize *args
6
+ super do |this|
7
+ this.ruby_opts.unshift " -r#{File.join('tlb', 'test_unit', 'mediator_inflection')} "
8
+ this.ruby_opts.unshift " -r#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'tlb'))} "
9
+ yield this if block_given?
10
+ end
11
+ end
12
+ end
data/lib/tlb.rb ADDED
@@ -0,0 +1,142 @@
1
+ require 'rubygems'
2
+ require 'open4'
3
+ require 'net/http'
4
+
5
+ TLB_RB_LIB = File.expand_path(File.dirname(__FILE__))
6
+ unless $LOAD_PATH.include? TLB_RB_LIB
7
+ $LOAD_PATH << TLB_RB_LIB
8
+ end
9
+
10
+ module Tlb
11
+ TLB_OUT_FILE = 'TLB_OUT_FILE'
12
+ TLB_ERR_FILE = 'TLB_ERR_FILE'
13
+ TLB_APP = 'TLB_APP'
14
+
15
+ module Balancer
16
+ TLB_BALANCER_PORT = 'TLB_BALANCER_PORT'
17
+ BALANCE_PATH = '/balance'
18
+ SUITE_TIME_REPORTING_PATH = '/suite_time'
19
+ SUITE_RESULT_REPORTING_PATH = '/suite_result'
20
+
21
+ def self.host
22
+ 'localhost'
23
+ end
24
+
25
+ def self.port
26
+ ENV[TLB_BALANCER_PORT]
27
+ end
28
+
29
+ def self.send path, data
30
+ Net::HTTP.start(host, port) do |h|
31
+ res = h.post(path, data)
32
+ res.value
33
+ res.body
34
+ end
35
+ end
36
+
37
+ def self.get path
38
+ Net::HTTP.get_response(host, path, port).body
39
+ end
40
+
41
+ def self.running?
42
+ get("/control/status") == "RUNNING"
43
+ rescue
44
+ false
45
+ end
46
+
47
+ def self.wait_for_start
48
+ loop do
49
+ begin
50
+ TCPSocket.new(host, port)
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.balance_and_order file_set
71
+ ensure_server_running
72
+ Balancer.send(Balancer::BALANCE_PATH, file_set.join("\n")).split("\n")
73
+ end
74
+
75
+ def self.suite_result suite_name, result
76
+ ensure_server_running
77
+ Balancer.send(Balancer::SUITE_RESULT_REPORTING_PATH, "#{suite_name}: #{result}")
78
+ end
79
+
80
+ def self.suite_time suite_name, mills
81
+ ensure_server_running
82
+ Balancer.send(Balancer::SUITE_TIME_REPORTING_PATH, "#{suite_name}: #{mills}")
83
+ end
84
+
85
+ def self.fail_as_balancer_is_not_running
86
+ raise "Balancer server must be started before tests are run."
87
+ end
88
+
89
+ def self.ensure_server_running
90
+ server_running? || fail_as_balancer_is_not_running
91
+ end
92
+
93
+ def self.server_running?
94
+ Balancer.running?
95
+ end
96
+
97
+ def self.root_dir
98
+ File.expand_path(File.join(File.dirname(__FILE__), ".."))
99
+ end
100
+
101
+ def self.tlb_jar
102
+ File.expand_path(Dir.glob(File.join(root_dir, "tlb-all*")).first)
103
+ end
104
+
105
+ def self.server_command
106
+ "java -jar #{tlb_jar}"
107
+ end
108
+
109
+ def self.write_to_file file_var, clob
110
+ File.open(ENV[file_var], 'a') do |h|
111
+ h.write(clob)
112
+ end
113
+ end
114
+
115
+ def self.start_server
116
+ ENV[TLB_APP] = 'com.github.tlb.balancer.BalancerInitializer'
117
+ @pid, input, out, err = Open4.popen4(server_command)
118
+ @out_pumper = stream_pumper_for(out, TLB_OUT_FILE)
119
+ @err_pumper = stream_pumper_for(err, TLB_ERR_FILE)
120
+ Balancer.wait_for_start
121
+ end
122
+
123
+ def self.stream_pumper_for stream, dump_file
124
+ Thread.new do
125
+ loop do
126
+ stream.eof? || write_to_file(dump_file, stream.read)
127
+ Thread.current[:stop_pumping] && break
128
+ sleep 1
129
+ end
130
+ end
131
+ end
132
+
133
+ def self.stop_server
134
+ Process.kill(Signal.list["TERM"], @pid)
135
+ @pid = nil
136
+ @out_pumper[:stop_pumping] = true
137
+ @err_pumper[:stop_pumping] = true
138
+ @out_pumper.join
139
+ @err_pumper.join
140
+ Process.wait
141
+ end
142
+ end
Binary file
@@ -0,0 +1,11 @@
1
+ $name="tlb-rspec2"
2
+ $framework='rspec-2.x'
3
+ require File.join(File.dirname(__FILE__), 'gem_common')
4
+
5
+ Gem::Specification.new do |s|
6
+ configure_tlb(s)
7
+
8
+ s.files = files('tests', File.join('lib', 'tlb', 'test_unit'))
9
+
10
+ s.add_runtime_dependency 'rspec', '>= 2.3.0'
11
+ end
@@ -0,0 +1,9 @@
1
+ $name="tlb-testunit"
2
+ $framework='test::unit'
3
+ require File.join(File.dirname(__FILE__), 'gem_common')
4
+
5
+ Gem::Specification.new do |s|
6
+ configure_tlb(s)
7
+
8
+ s.files = files('tests', File.join('lib', 'tlb', 'rspec'))
9
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tlb-testunit
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Janmejay Singh
14
+ - Pavan KS
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-12-22 00:00:00 +05:30
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: open4
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 21
31
+ segments:
32
+ - 1
33
+ - 0
34
+ - 1
35
+ version: 1.0.1
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: rake
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 3
47
+ segments:
48
+ - 0
49
+ version: "0"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ description: |
53
+ TLB ruby implementation base, which provides support for load balancing tests written in test::unit.
54
+ TLB_rb test suite is not bundled, please check http://github.com/test-load-balancer/tlb_rb for tests.
55
+ Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
56
+
57
+ email: singh.janmejay@gmail.com;itspanzi@gmail.com
58
+ executables: []
59
+
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - README.markdown
64
+ files:
65
+ - .emacs_project
66
+ - .gitignore
67
+ - .gitmodules
68
+ - README.markdown
69
+ - Rakefile
70
+ - gem_common.rb
71
+ - lib/tasks/tlb.rake
72
+ - lib/tlb.rb
73
+ - lib/tlb/run_data.rb
74
+ - lib/tlb/test_unit/mediator_inflection.rb
75
+ - lib/tlb/test_unit/test_observer.rb
76
+ - lib/tlb/test_unit/test_splitter.rb
77
+ - lib/tlb/test_unit/test_task.rb
78
+ - tlb-rspec2.gemspec
79
+ - tlb-testunit.gemspec
80
+ - tlb-all-gv0.2-9-g1f1a4aa.jar
81
+ has_rdoc: true
82
+ homepage: http://github.com/test-load-balancer/tlb_rb
83
+ licenses: []
84
+
85
+ post_install_message: |
86
+ -------------------------------------------------------------------------
87
+ Documentation: Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
88
+ -----------------------------
89
+ Example: https://github.com/test-load-balancer/sample_projects has examples projects and shell script to demonstrate a typical build(by starting a local tlb server, and executing two partitions locally). While partitions in these examples execute one after another, in an actual CI/pre-checkin build, they will actually run parallely on different machines.
90
+ Its a good idea to play with the environment variables values being used in these shell-scripts to understand how they affect TLB's behaviour. You may want to check https://github.com/test-load-balancer/tlb/wiki/Configuration-Variables, which documents each variable and its effect.
91
+ -----------------------------
92
+ Issue tracker: Please report bugs/enhancements/feature-requests at http://code.google.com/p/tlb/issues/list. Github, Rubyforge or any other issue trackers are not monitored or updated.
93
+ -------------------------------------------------------------------------
94
+
95
+ rdoc_options:
96
+ - --charset=UTF-8
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project: tlb-rb
120
+ rubygems_version: 1.3.7
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: tlb-testunit-0.1.1
124
+ test_files: []
125
+