tlb-rspec1 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.
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,30 @@
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).
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ Spec::Rake::SpecTask.new(:spec) do |t|
4
+ t.spec_files = FileList['spec/**/*_spec.rb']
5
+ end
6
+
7
+ task :build_tlb do
8
+ Dir.glob("tlb-all*.jar").each { |jar| FileUtils.rm(jar) }
9
+ sh 'ant -f tlb/build.xml package'
10
+ Dir.glob('tlb/target/tlb-all*').each { |file| FileUtils.copy(file, ".") }
11
+ end
12
+
13
+ task :package do
14
+ `gem build tlb-rspec1.gemspec`
15
+ 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/, '').gsub(/-rspec-1$/, '')
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,70 @@
1
+ require 'spec/runner/formatter/silent_formatter'
2
+
3
+ class Tlb::SpecFormatter < Spec::Runner::Formatter::SilentFormatter
4
+ class Suite < Struct.new(:file_name, :start_time, :end_time, :failed)
5
+ MILLS_PER_SEC = 1000
6
+
7
+ def initialize(file_name, start_time)
8
+ super(file_name, start_time, start_time, false)
9
+ end
10
+
11
+ def for_file? new_file
12
+ File.identical?(file_name, new_file)
13
+ end
14
+
15
+ def run_time
16
+ ((end_time - start_time)*MILLS_PER_SEC).to_i
17
+ end
18
+
19
+ def report_to_tlb
20
+ rel_file_name = Tlb.relative_file_path(file_name)
21
+ Tlb.suite_time(rel_file_name, run_time)
22
+ Tlb.suite_result(rel_file_name, failed)
23
+ end
24
+ end
25
+
26
+ def initialize(*args)
27
+ super(*args)
28
+ @suites = []
29
+ end
30
+
31
+ def example_group_started(example_proxy_group)
32
+ file_name = example_file_name(example_proxy_group)
33
+ unless (@suites.last && @suites.last.for_file?(file_name))
34
+ @suites << Tlb::SpecFormatter::Suite.new(file_name, Time.now)
35
+ end
36
+ end
37
+
38
+ def example_passed(example_proxy)
39
+ record_suite_data(example_proxy)
40
+ end
41
+
42
+ def example_failed(example_proxy, *ignore)
43
+ record_suite_data(example_proxy) do |suite|
44
+ suite.failed = true
45
+ end
46
+ end
47
+
48
+ def example_pending(example_proxy, *ignore)
49
+ record_suite_data(example_proxy)
50
+ end
51
+
52
+ def start_dump
53
+ @suites.each do |suite_time|
54
+ suite_time.report_to_tlb
55
+ end
56
+ end
57
+
58
+ private
59
+ def record_suite_data example_proxy
60
+ file_name = example_file_name(example_proxy)
61
+ if (suite = @suites.last) #stupid framework :: retarded fix (this is necessary since rspec creates example_proxies for every example it runs, as though its an independent spec-group)
62
+ suite.end_time = Time.now
63
+ block_given? && yield(suite)
64
+ end
65
+ end
66
+
67
+ def example_file_name example_proxy
68
+ example_proxy.location ? (@last_known_file = example_proxy.location.scan(/^(.+?):\d+(:.*)?$/).flatten.first) : @last_known_file
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ class Tlb::SpecTask < Spec::Rake::SpecTask
4
+ attr_accessor :tlb_out
5
+
6
+ def initialize *args
7
+ path_to_tlb = File.expand_path(File.join(File.dirname(__FILE__), '..', 'tlb'))
8
+ path_to_spec_formatter = File.expand_path(File.join(File.dirname(__FILE__), 'spec_formatter'))
9
+ self.tlb_out = '/dev/null'
10
+ super do |this|
11
+ yield this if block_given?
12
+ this.spec_opts.unshift "--require #{path_to_tlb},#{path_to_spec_formatter} --format 'Tlb::SpecFormatter:#{this.tlb_out}'"
13
+ end
14
+ end
15
+
16
+ alias_method :rspec_spec_file_list, :spec_file_list
17
+
18
+ def spec_file_list
19
+ balanced_and_reordered = Tlb.balance_and_order(rspec_spec_file_list.to_a)
20
+ FileList[*balanced_and_reordered]
21
+ end
22
+ end
data/lib/tlb.rb ADDED
@@ -0,0 +1,135 @@
1
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "tlb"))
2
+ require 'rubygems'
3
+ require 'open4'
4
+ require 'net/http'
5
+
6
+ module Tlb
7
+ TLB_OUT_FILE = 'TLB_OUT_FILE'
8
+ TLB_ERR_FILE = 'TLB_ERR_FILE'
9
+ TLB_APP = 'TLB_APP'
10
+
11
+ module Balancer
12
+ TLB_BALANCER_PORT = 'TLB_BALANCER_PORT'
13
+ BALANCE_PATH = '/balance'
14
+ SUITE_TIME_REPORTING_PATH = '/suite_time'
15
+ SUITE_RESULT_REPORTING_PATH = '/suite_result'
16
+
17
+ def self.host
18
+ 'localhost'
19
+ end
20
+
21
+ def self.port
22
+ ENV[TLB_BALANCER_PORT]
23
+ end
24
+
25
+ def self.send path, data
26
+ Net::HTTP.start(host, port) do |h|
27
+ res = h.post(path, data)
28
+ res.value
29
+ res.body
30
+ end
31
+ end
32
+
33
+ def self.get path
34
+ Net::HTTP.get_response(host, path, port).body
35
+ end
36
+
37
+ def self.running?
38
+ get("/control/status") == "RUNNING"
39
+ rescue
40
+ false
41
+ end
42
+
43
+ def self.wait_for_start
44
+ loop do
45
+ begin
46
+ TCPSocket.new(host, port)
47
+ break if running?
48
+ rescue
49
+ #ignore
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def self.relative_file_path file_name
56
+ abs_file_name = File.expand_path(file_name)
57
+ rel_file_name = abs_file_name.sub(/^#{Dir.pwd}/, '.')
58
+ end
59
+
60
+ def self.balance_and_order file_set
61
+ ensure_server_running
62
+ Balancer.send(Balancer::BALANCE_PATH,
63
+ file_set.map do |file_path|
64
+ Tlb.relative_file_path(file_path)
65
+ end.join("\n")).split("\n")
66
+ end
67
+
68
+ def self.suite_result suite_name, result
69
+ ensure_server_running
70
+ Balancer.send(Balancer::SUITE_RESULT_REPORTING_PATH, "#{suite_name}: #{result}")
71
+ end
72
+
73
+ def self.suite_time suite_name, mills
74
+ ensure_server_running
75
+ Balancer.send(Balancer::SUITE_TIME_REPORTING_PATH, "#{suite_name}: #{mills}")
76
+ end
77
+
78
+ def self.fail_as_balancer_is_not_running
79
+ raise "Balancer server must be started before tests are run."
80
+ end
81
+
82
+ def self.ensure_server_running
83
+ server_running? || fail_as_balancer_is_not_running
84
+ end
85
+
86
+ def self.server_running?
87
+ Balancer.running?
88
+ end
89
+
90
+ def self.root_dir
91
+ File.expand_path(File.join(File.dirname(__FILE__), ".."))
92
+ end
93
+
94
+ def self.tlb_jar
95
+ File.expand_path(Dir.glob(File.join(root_dir, "tlb-all*")).first)
96
+ end
97
+
98
+ def self.server_command
99
+ "java -jar #{tlb_jar}"
100
+ end
101
+
102
+ def self.write_to_file file_var, clob
103
+ File.open(ENV[file_var], 'a') do |h|
104
+ h.write(clob)
105
+ end
106
+ end
107
+
108
+ def self.start_server
109
+ ENV[TLB_APP] = 'com.github.tlb.balancer.BalancerInitializer'
110
+ @pid, input, out, err = Open4.popen4(server_command)
111
+ @out_pumper = stream_pumper_for(out, TLB_OUT_FILE)
112
+ @err_pumper = stream_pumper_for(err, TLB_ERR_FILE)
113
+ Balancer.wait_for_start
114
+ end
115
+
116
+ def self.stream_pumper_for stream, dump_file
117
+ Thread.new do
118
+ loop do
119
+ stream.eof? || write_to_file(dump_file, stream.read)
120
+ Thread.current[:stop_pumping] && break
121
+ sleep 1
122
+ end
123
+ end
124
+ end
125
+
126
+ def self.stop_server
127
+ Process.kill(Signal.list["TERM"], @pid)
128
+ @pid = nil
129
+ @out_pumper[:stop_pumping] = true
130
+ @err_pumper[:stop_pumping] = true
131
+ @out_pumper.join
132
+ @err_pumper.join
133
+ Process.wait
134
+ end
135
+ end
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+ while [[ true ]] ;
3
+ do
4
+ echo "hello out"
5
+ echo "hello err" 1>&2
6
+ sleep 1
7
+ done
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'mocha'
3
+ require 'spec'
4
+ require 'rake'
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__), "..", "lib")
6
+ require 'tlb'
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :mocha
10
+ end
11
+
12
+ def tmp_file file_name
13
+ path = File.join(Dir.tmpdir, file_name)
14
+ file = File.new(path, 'w')
15
+ File.truncate path, 0
16
+ file.close
17
+ file
18
+ end
19
+
@@ -0,0 +1,140 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+ require 'spec_formatter'
3
+ require 'spec/example/example_proxy'
4
+ require 'spec/example/example_group_proxy'
5
+
6
+ describe Tlb::SpecFormatter do
7
+ before :all do
8
+ FileUtils.mkdir_p(@dir = Dir.pwd + "/tmp/foo/../bar/..")
9
+ end
10
+
11
+ before do
12
+ @group_1, @file_1 = stubbed_group("baz/group1")
13
+ @group_2, @file_2 = stubbed_group("group2")
14
+ @group_3, @file_3 = stubbed_group("group3")
15
+ @group_proxy_1 = Spec::Example::ExampleGroupProxy.new(@group_1)
16
+ @group_proxy_2 = Spec::Example::ExampleGroupProxy.new(@group_2)
17
+ @group_proxy_3 = Spec::Example::ExampleGroupProxy.new(@group_3)
18
+ @formatter = Tlb::SpecFormatter.new(nil, nil)
19
+ end
20
+
21
+ def stubbed_group group_name
22
+ grp = stub(group_name)
23
+ grp.expects(:description).returns("#{group_name} desc")
24
+ grp.expects(:nested_descriptions).returns("#{group_name} nested desc")
25
+ grp.expects(:example_proxies).returns("#{group_name} example proxies")
26
+ grp.expects(:options).returns({:name => group_name})
27
+
28
+ file_name = "#{@dir}/#{group_name}.rb"
29
+ FileUtils.mkdir_p(File.dirname(file_name))
30
+ File.open(file_name, 'w') do |h|
31
+ h.write("something")
32
+ end
33
+ rel_file_name = File.expand_path(file_name).sub(Dir.pwd, '.')
34
+ grp.expects(:location).times(2).returns(file_name + ":4")
35
+
36
+ [grp, rel_file_name]
37
+ end
38
+
39
+ it "should be silent formatter" do
40
+ @formatter.should be_a(Spec::Runner::Formatter::SilentFormatter)
41
+ end
42
+
43
+ it "should use last finished example's time" do
44
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 10))
45
+ @formatter.example_group_started(@group_proxy_1)
46
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 20))
47
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group1 spec 1", {}, "#{@dir}/baz/group1.rb:12"))
48
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 22))
49
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group1 spec 2", {}, "#{@dir}/baz/group1.rb:40"), 1, "ignore")
50
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 29))
51
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group1 spec 3", {}, "#{@dir}/baz/group1.rb:55"), "some reason")
52
+
53
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 6, 00))
54
+ @formatter.example_group_started(@group_proxy_2)
55
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 6, 12))
56
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group2 spec 1", {}, "#{@dir}/group2.rb:5"), "some reason")
57
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 6, 25))
58
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group2 spec 2", {}, "#{@dir}/group2.rb:38"))
59
+
60
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 7, 15))
61
+ @formatter.example_group_started(@group_proxy_3)
62
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 8, 12))
63
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group3 spec 1", {}, "#{@dir}/group3.rb:45"), "some reason")
64
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 8, 55))
65
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group3 spec 2", {}, "#{@dir}/group3.rb:80"), 3, "ignore")
66
+
67
+ Tlb.stubs(:suite_result)
68
+
69
+ Tlb.expects(:suite_time).with(@file_1, 19000)
70
+ Tlb.expects(:suite_time).with(@file_2, 25000)
71
+ Tlb.expects(:suite_time).with(@file_3, 100000)
72
+
73
+ @formatter.start_dump
74
+ end
75
+
76
+ it "should report suite result to tlb" do
77
+ @formatter.example_group_started(@group_proxy_1)
78
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group1 spec 1", {}, "#{@dir}/baz/group1.rb:12"))
79
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group1 spec 2", {}, "#{@dir}/baz/group1.rb:40"), 1, "ignore")
80
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group1 spec 3", {}, "#{@dir}/baz/group1.rb:55"), "some reason")
81
+
82
+ @formatter.example_group_started(@group_proxy_2)
83
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group2 spec 1", {}, "#{@dir}/group2.rb:5"), "some reason")
84
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group2 spec 2", {}, "#{@dir}/group2.rb:38"))
85
+
86
+ @formatter.example_group_started(@group_proxy_3)
87
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group3 spec 1", {}, "#{@dir}/group3.rb:45"), "some reason")
88
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group3 spec 2", {}, "#{@dir}/group3.rb:80"), 3, "ignore")
89
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group3 spec 3", {}, "#{@dir}/group3.rb:85"))
90
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group3 spec 4", {}, "#{@dir}/group3.rb:103"))
91
+
92
+ Tlb.stubs(:suite_time)
93
+
94
+ Tlb.expects(:suite_result).with(@file_1, true)
95
+ Tlb.expects(:suite_result).with(@file_2, false)
96
+ Tlb.expects(:suite_result).with(@file_3, true)
97
+
98
+ @formatter.start_dump
99
+ end
100
+
101
+ it "should parse example_file_name" do
102
+ @formatter.send(:example_file_name, Spec::Example::ExampleProxy.new("some method call inside spec", {}, "./spec/baz_quux.rb:9")).should == "./spec/baz_quux.rb"
103
+ @formatter.send(:example_file_name, Spec::Example::ExampleProxy.new("some method call inside spec", {}, "./spec/foo_bar_baz.rb:9:in `should_quux'")).should == "./spec/foo_bar_baz.rb"
104
+ end
105
+
106
+ it "should report suite result for last heard file name when it received example_proxy having no location" do
107
+ @formatter.example_group_started(@group_proxy_1)
108
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("before(:all)"))
109
+ Tlb.stubs(:suite_time)
110
+
111
+ Tlb.expects(:suite_result).with(@file_1, true)
112
+
113
+ @formatter.start_dump
114
+ end
115
+
116
+ it "should share the same suite when example_group starts twice(this happens in nested describe blocks)" do
117
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 10))
118
+ @formatter.example_group_started(@group_proxy_1)
119
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 20))
120
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group1 spec 1", {}, "#{@dir}/baz/group1.rb:12"))
121
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 22))
122
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group1 spec 2", {}, "#{@dir}/baz/group1.rb:40"), 1, "ignore")
123
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 5, 29))
124
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group1 spec 3", {}, "#{@dir}/baz/group1.rb:55"), "some reason")
125
+
126
+ @formatter.example_group_started(@group_proxy_1)
127
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 6, 12))
128
+ @formatter.example_failed(Spec::Example::ExampleProxy.new("group1 spec 4(nested)", {}, "#{@dir}/baz/group1.rb:100"), 1, "foo_bar")
129
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 6, 25))
130
+ @formatter.example_pending(Spec::Example::ExampleProxy.new("group1 spec 4(nested)", {}, "#{@dir}/baz/group1.rb:130"), "some pending")
131
+ Time.expects(:now).returns(Time.local( 2010, "jul", 16, 12, 7, 15))
132
+ @formatter.example_passed(Spec::Example::ExampleProxy.new("group1 spec 4(nested)", {}, "#{@dir}/baz/group1.rb:145"))
133
+
134
+ Tlb.stubs(:suite_result)
135
+
136
+ Tlb.expects(:suite_time).with(@file_1, 125000)
137
+ @formatter.start_dump
138
+ end
139
+
140
+ end
@@ -0,0 +1,40 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
2
+ require 'spec_task'
3
+
4
+ describe Tlb::SpecTask do
5
+ before(:all) do
6
+ @path_to_tlb = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'tlb'))
7
+ @path_to_spec_formatter = File.expand_path(File.join(@path_to_tlb, 'spec_formatter'))
8
+ end
9
+
10
+ it "should return balanced and ordered subset" do
11
+ @task = Tlb::SpecTask.new
12
+ Tlb.stubs(:start_unless_running)
13
+ @task.expects(:rspec_spec_file_list).returns(FileList['foo.rb', 'bar.rb', 'baz.rb', 'quux.rb'])
14
+ Tlb.stubs(:balance_and_order).with(['foo.rb', 'bar.rb', 'baz.rb', 'quux.rb']).returns(['quux.rb', 'foo.rb'])
15
+ balanced_list = @task.spec_file_list
16
+ balanced_list.should be_a(Rake::FileList)
17
+ balanced_list.to_a.should == ['quux.rb', 'foo.rb']
18
+ end
19
+
20
+ it "should hookup formatter so feedback is posted" do
21
+ @task = Tlb::SpecTask.new
22
+ @task.spec_opts.should == ["--require #{@path_to_tlb},#{@path_to_spec_formatter} --format 'Tlb::SpecFormatter:/dev/null'"]
23
+ end
24
+
25
+ it "should honor user specified attributes" do
26
+ @task = Tlb::SpecTask.new(:foo) do |t|
27
+ t.spec_opts << "--require foo_bar"
28
+ t.spec_opts << "--require baz_quux"
29
+ end
30
+ @task.spec_opts.should == ["--require #{@path_to_tlb},#{@path_to_spec_formatter} --format 'Tlb::SpecFormatter:/dev/null'", "--require foo_bar", "--require baz_quux"]
31
+ @task.name.should == :foo
32
+ end
33
+
34
+ it "should use specified output file for tlb's spec_formatter" do
35
+ @task = Tlb::SpecTask.new(:foo) do |t|
36
+ t.tlb_out = "/tmp/tlb_spec_formatter_out"
37
+ end
38
+ @task.spec_opts.should == ["--require #{@path_to_tlb},#{@path_to_spec_formatter} --format 'Tlb::SpecFormatter:/tmp/tlb_spec_formatter_out'"]
39
+ end
40
+ end
@@ -0,0 +1,146 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'open4'
3
+ require 'parsedate'
4
+ require 'tmpdir'
5
+ require 'webrick'
6
+
7
+ describe Tlb do
8
+ URL = "http://localhost:7019"
9
+ JOB_NAME = "foo"
10
+ TLB_BALANCER_PORT = '9173'
11
+ before :all do
12
+ ENV['TLB_APP'] = 'com.github.tlb.server.TlbServerInitializer'
13
+ @pid, i, o, e = Open4.popen4(Tlb.server_command)
14
+ end
15
+
16
+ after :all do
17
+ Process.kill(Signal.list['KILL'], @pid)
18
+ end
19
+
20
+ it "should wait for balancer server to come up before returning from start_server" do
21
+ Tlb::Balancer.expects(:wait_for_start)
22
+ Open4.stubs(:popen4)
23
+ Tlb.start_server
24
+ end
25
+
26
+ describe "using server" do
27
+ before do
28
+ ENV[Tlb::TLB_OUT_FILE] = (@out_file = tmp_file('tlb_out_file').path)
29
+ ENV[Tlb::TLB_ERR_FILE] = (@err_file = tmp_file('tlb_err_file').path)
30
+ Tlb.server_running?.should be_false #precondition (the server must be started if not running)
31
+
32
+ ENV['TLB_BALANCER_PORT'] = TLB_BALANCER_PORT
33
+ ENV['TLB_URL'] = URL
34
+ ENV['TALK_TO_SERVICE'] = "com.github.tlb.service.TalkToTlbServer"
35
+ ENV['TLB_JOB_NAME'] = JOB_NAME
36
+ ENV['TOTAL_PARTITIONS'] = '2'
37
+ ENV['JOB_VERSION'] = '123'
38
+ ENV['TLB_CRITERIA'] = 'com.github.tlb.splitter.CountBasedTestSplitterCriteria'
39
+ end
40
+
41
+ after do
42
+ Tlb.server_running?.should be_true #api calls need not worry about killing it
43
+ Tlb.stop_server
44
+ end
45
+
46
+ it "should balance for first partition" do
47
+ ENV['PARTITION_NUMBER'] = '1'
48
+ Tlb.start_server
49
+ Tlb.balance_and_order(["foo/bar.rb", "foo/baz.rb", "bar/foo.rb", "bar/quux.rb"]).should == ["./foo/bar.rb", "./foo/baz.rb"]
50
+ end
51
+
52
+ it "should balance for second partition" do
53
+ ENV['PARTITION_NUMBER'] = '2'
54
+ Tlb.start_server
55
+ Tlb.balance_and_order(["foo/bar.rb", "foo/baz.rb", "bar/foo.rb", "bar/quux.rb"]).should == ["./bar/foo.rb", "./bar/quux.rb"]
56
+ end
57
+
58
+ it "should balance with file path names relative to working dir" do
59
+ ENV['PARTITION_NUMBER'] = '1'
60
+ Tlb.start_server
61
+ Tlb.balance_and_order(["foo/hi/../baz/quux/../hello/../../bar.rb", "foo/bar/../baz.rb", "bar/baz/quux/../../foo.rb", "bar/quux.rb"]).should == ["./foo/bar.rb", "./foo/baz.rb"]
62
+ end
63
+
64
+ describe "thats already running" do
65
+ before do
66
+ Tlb.start_server
67
+ end
68
+
69
+ it "should publish suite result" do
70
+ Tlb.suite_result("foo/bar.rb", true)
71
+ Tlb.suite_result("foo/baz.rb", false)
72
+ Tlb.suite_result("foo/quux.rb", true)
73
+ get_from_tlb_server("suite_result").should include("foo/bar.rb: true", "foo/baz.rb: false", "foo/quux.rb: true")
74
+ end
75
+
76
+ it "should publish suite time" do
77
+ Tlb.suite_time("foo/bar.rb", 102)
78
+ Tlb.suite_time("foo/baz.rb", 3599)
79
+ Tlb.suite_time("foo/quux.rb", 2010)
80
+ get_from_tlb_server("suite_time").should include("foo/bar.rb: 102", "foo/baz.rb: 3599", "foo/quux.rb: 2010")
81
+ end
82
+
83
+ def get_from_tlb_server path
84
+ body = Net::HTTP.get(URI.parse("#{URL}/#{JOB_NAME}/#{path}"))
85
+ body.split("\n")
86
+ end
87
+
88
+ it "should use send method to balance" do
89
+ Tlb::Balancer.expects(:send).with(Tlb::Balancer::BALANCE_PATH, "./foo/bar.rb\n./foo/baz.rb").returns("foo\nbar")
90
+ Tlb.balance_and_order(["foo/bar.rb", "foo/baz.rb"]).should == ["foo", "bar"]
91
+ end
92
+
93
+ it "should use send method to post results" do
94
+ Tlb::Balancer.expects(:send).with(Tlb::Balancer::SUITE_RESULT_REPORTING_PATH, "foo/bar.rb: false")
95
+ Tlb.suite_result("foo/bar.rb", false)
96
+ end
97
+
98
+ it "should use send method to post time" do
99
+ Tlb::Balancer.expects(:send).with(Tlb::Balancer::SUITE_TIME_REPORTING_PATH, "foo/bar.rb: 42")
100
+ Tlb.suite_time("foo/bar.rb", 42)
101
+ end
102
+
103
+ it "should raise exception when call to tlb fails" do
104
+ lambda do
105
+ Tlb::Balancer.send("/foo", "bar")
106
+ end.should raise_error(Net::HTTPServerException, '404 "The server has not found anything matching the request URI"')
107
+ end
108
+ end
109
+ end
110
+
111
+ describe :wait_for_server_to_start do
112
+ class CtrlStatus < WEBrick::HTTPServlet::AbstractServlet
113
+ def do_GET(request, response)
114
+ response.status = 200
115
+ response['Content-Type'] = 'text/plain'
116
+ response.body = 'RUNNING'
117
+ end
118
+ end
119
+ before do
120
+ @server = nil
121
+ ENV['TLB_BALANCER_PORT'] = TLB_BALANCER_PORT
122
+ end
123
+
124
+ after do
125
+ @server.shutdown
126
+ end
127
+
128
+ it "should wait until socket has a listener" do
129
+ @wait_completed = false
130
+ before_start = Time.now
131
+ wait_thread = Thread.new do
132
+ sleep 3
133
+ @wait_completed = true
134
+ @server = WEBrick::HTTPServer.new(:Port => TLB_BALANCER_PORT,
135
+ :Logger => WEBrick::BasicLog.new(tmp_file('tlb_webrick_log').path),
136
+ :AccessLog => WEBrick::BasicLog.new(tmp_file('tlb_webrick_access_log').path))
137
+ @server.mount '/control/status', CtrlStatus
138
+ @server.start
139
+ end
140
+ @wait_completed.should be_false
141
+ Tlb::Balancer.wait_for_start
142
+ @wait_completed.should be_true
143
+ Time.now.should > (before_start + 3)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,89 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ require 'open4'
3
+ require 'parsedate'
4
+ require 'tmpdir'
5
+
6
+ describe Tlb do
7
+ before do
8
+ ENV[Tlb::TLB_OUT_FILE] = (@out_file = tmp_file('tlb_out_file').path)
9
+ ENV[Tlb::TLB_ERR_FILE] = (@err_file = tmp_file('tlb_err_file').path)
10
+ Tlb::Balancer.stubs(:wait_for_start)
11
+ end
12
+
13
+ MOCK_PROCESS_ID = 33040
14
+ SIG_TERM = 15
15
+
16
+ it "should terminate process when stop called" do
17
+ Tlb.instance_variable_set('@pid', MOCK_PROCESS_ID)
18
+ Tlb.instance_variable_set('@out_pumper', Thread.new { })
19
+ Tlb.instance_variable_set('@err_pumper', Thread.new { })
20
+
21
+ Process.expects(:kill).with(SIG_TERM, MOCK_PROCESS_ID)
22
+ Process.expects(:wait).with()
23
+
24
+ Tlb.stop_server
25
+ end
26
+
27
+ def times_of_output content, stream_name
28
+ content.split("\n").map { |line| line.gsub(stream_name, '') }.map do |line|
29
+ year, month, day_of_month, hour, minute, second, timezone, day_of_week = ParseDate.parsedate(line)
30
+ Time.local(year, month, day_of_month, hour, minute, second)
31
+ end
32
+ end
33
+
34
+ it "should generate the right command to run tlb balancer server" do
35
+ tlb_jar = File.expand_path(Dir.glob(File.join(File.join(File.dirname(__FILE__), ".."), "tlb-all*")).first)
36
+ Tlb.server_command.should == "java -jar #{tlb_jar}"
37
+ end
38
+
39
+ describe :integration_test do
40
+ it "should pump both error and out to the file" do
41
+ Tlb.stubs(:wait_for_start)
42
+ Tlb.expects(:server_command).returns(File.join(File.dirname(__FILE__), "fixtures", "foo.sh"))
43
+ Tlb.start_server
44
+ sleep 2
45
+ Tlb.stop_server
46
+ File.read(@out_file).should include("hello out\n")
47
+ File.read(@err_file).should include("hello err\n")
48
+ end
49
+ end
50
+
51
+ it "should fail of server not running" do
52
+ Tlb.expects(:server_running?).returns(false)
53
+ lambda { Tlb.ensure_server_running }.should raise_error('Balancer server must be started before tests are run.')
54
+ end
55
+
56
+ it "should not start server if running" do
57
+ Tlb.expects(:server_running?).returns(true)
58
+ Tlb.expects(:start_server).never
59
+ Tlb.ensure_server_running
60
+ end
61
+
62
+ describe "env var" do
63
+ before do
64
+ module Open4
65
+ class << self
66
+ alias_method :old_popen4, :popen4
67
+ end
68
+
69
+ def self.popen4 command
70
+ ENV['TLB_APP'].should == "com.github.tlb.balancer.BalancerInitializer"
71
+ end
72
+ end
73
+ end
74
+
75
+ after do
76
+ module Open4
77
+ class << self
78
+ alias_method :popen4, :old_popen4
79
+ end
80
+ end
81
+ end
82
+
83
+ it "should set TLB_APP to point to balancer before starting the server" do
84
+ ENV['TLB_APP'] = "foo"
85
+ Tlb.stubs(:server_command).returns("foo bar")
86
+ Tlb.start_server
87
+ end
88
+ end
89
+ end
Binary file
@@ -0,0 +1,11 @@
1
+ $name="tlb-rspec1"
2
+ $framework='rspec-1.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_development_dependency 'rspec', '>= 1.3.0'
11
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tlb-rspec1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
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
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 27
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 0
65
+ version: 1.3.0
66
+ type: :development
67
+ version_requirements: *id003
68
+ description: |
69
+ TLB ruby implementation base, which provides support for load balancing tests written in rspec-1.x.
70
+ TLB_rb test suite is not bundled, please check http://github.com/test-load-balancer/tlb_rb for tests.
71
+ Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
72
+
73
+ email: singh.janmejay@gmail.com;itspanzi@gmail.com
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files:
79
+ - README.markdown
80
+ files:
81
+ - .gitignore
82
+ - .gitmodules
83
+ - README.markdown
84
+ - Rakefile
85
+ - gem_common.rb
86
+ - lib/tasks/tlb.rake
87
+ - lib/tlb.rb
88
+ - lib/tlb/spec_formatter.rb
89
+ - lib/tlb/spec_task.rb
90
+ - spec/fixtures/foo.sh
91
+ - spec/spec_helper.rb
92
+ - spec/tlb/spec_formatter_spec.rb
93
+ - spec/tlb/spec_task_spec.rb
94
+ - spec/tlb_http_communication_spec.rb
95
+ - spec/tlb_process_control_spec.rb
96
+ - tlb-rspec1.gemspec
97
+ - tlb-all-gv0.2-9-g1f1a4aa.jar
98
+ has_rdoc: true
99
+ homepage: http://github.com/test-load-balancer/tlb_rb
100
+ licenses: []
101
+
102
+ post_install_message: |
103
+ -------------------------------------------------------------------------
104
+ Documentation: Detailed configuration documentation can be found at https://github.com/test-load-balancer/tlb/wiki.
105
+ -----------------------------
106
+ 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.
107
+ 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.
108
+ -----------------------------
109
+ 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.
110
+ -------------------------------------------------------------------------
111
+
112
+ rdoc_options:
113
+ - --charset=UTF-8
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ hash: 3
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ requirements: []
135
+
136
+ rubyforge_project: tlb-rb
137
+ rubygems_version: 1.3.7
138
+ signing_key:
139
+ specification_version: 3
140
+ summary: tlb-rspec1-0.1.0-rspec-1
141
+ test_files: []
142
+