borg 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +30 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +23 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/borg.gemspec +72 -0
- data/lib/borg/borg_abstract_adapter.rb +138 -0
- data/lib/borg/borg_config.rb +7 -0
- data/lib/borg/borg_cucumber.rb +28 -0
- data/lib/borg/borg_git.rb +29 -0
- data/lib/borg/borg_messages.rb +13 -0
- data/lib/borg/borg_requestor.rb +42 -0
- data/lib/borg/borg_server.rb +89 -0
- data/lib/borg/borg_tasks.rake +67 -0
- data/lib/borg/borg_test_unit.rb +23 -0
- data/lib/borg/borg_worker.rb +102 -0
- data/lib/borg/railtie.rb +23 -0
- data/lib/borg.rb +5 -0
- metadata +161 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
gem 'eventmachine'
|
7
|
+
gem 'redis'
|
8
|
+
|
9
|
+
# Add dependencies to develop your gem here.
|
10
|
+
# Include everything needed to run rake, tests, features, etc.
|
11
|
+
group :development do
|
12
|
+
gem "bundler", "~> 1.0.0"
|
13
|
+
gem "jeweler", "~> 1.5.2"
|
14
|
+
gem "rspec"
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
eventmachine (0.12.10)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.5.2)
|
8
|
+
bundler (~> 1.0.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rake
|
11
|
+
rake (0.8.7)
|
12
|
+
redis (2.1.1)
|
13
|
+
rspec (2.5.0)
|
14
|
+
rspec-core (~> 2.5.0)
|
15
|
+
rspec-expectations (~> 2.5.0)
|
16
|
+
rspec-mocks (~> 2.5.0)
|
17
|
+
rspec-core (2.5.1)
|
18
|
+
rspec-expectations (2.5.0)
|
19
|
+
diff-lcs (~> 1.1.2)
|
20
|
+
rspec-mocks (2.5.0)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
bundler (~> 1.0.0)
|
27
|
+
eventmachine
|
28
|
+
jeweler (~> 1.5.2)
|
29
|
+
redis
|
30
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Hemant Kumar
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= Borg
|
2
|
+
|
3
|
+
Borg is a distributed test runner for running you unit/functionals tests, specs or cucumber scenarios, across a network of machines.
|
4
|
+
|
5
|
+
It is written using EventMachine and Redis and has rather very simple design at its heart.
|
6
|
+
More details forthcoming..
|
7
|
+
|
8
|
+
|
9
|
+
== Contributing to tickle
|
10
|
+
|
11
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
12
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
13
|
+
* Fork the project
|
14
|
+
* Start a feature/bugfix branch
|
15
|
+
* Commit and push until you are happy with your contribution
|
16
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
17
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
18
|
+
|
19
|
+
== Copyright
|
20
|
+
|
21
|
+
Copyright (c) 2011 Hemant Kumar. See LICENSE.txt for
|
22
|
+
further details.
|
23
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
gem.name = "borg"
|
15
|
+
gem.homepage = "http://github.com/gnufied/borg"
|
16
|
+
gem.license = "MIT"
|
17
|
+
gem.summary = %Q{A distributed Test Suite runner for Rails, using Eventmachine and Redis}
|
18
|
+
gem.description = %Q{A distributed Test Suite runner for Rails, using Eventmachine and Redis}
|
19
|
+
gem.email = "hkumar@crri.co.in"
|
20
|
+
gem.authors = ["Hemant Kumar", "Karunakar"]
|
21
|
+
end
|
22
|
+
|
23
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
task :default => :test
|
33
|
+
|
34
|
+
require 'rake/rdoctask'
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
37
|
+
|
38
|
+
rdoc.rdoc_dir = 'rdoc'
|
39
|
+
rdoc.title = "borg #{version}"
|
40
|
+
rdoc.rdoc_files.include('README*')
|
41
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
42
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.6
|
data/borg.gemspec
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{borg}
|
8
|
+
s.version = "0.0.6"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Hemant Kumar", "Karunakar"]
|
12
|
+
s.date = %q{2011-02-07}
|
13
|
+
s.description = %q{A distributed Test Suite runner for Rails, using Eventmachine and Redis}
|
14
|
+
s.email = %q{hkumar@crri.co.in}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"borg.gemspec",
|
28
|
+
"lib/borg.rb",
|
29
|
+
"lib/borg/borg_abstract_adapter.rb",
|
30
|
+
"lib/borg/borg_config.rb",
|
31
|
+
"lib/borg/borg_cucumber.rb",
|
32
|
+
"lib/borg/borg_git.rb",
|
33
|
+
"lib/borg/borg_messages.rb",
|
34
|
+
"lib/borg/borg_requestor.rb",
|
35
|
+
"lib/borg/borg_server.rb",
|
36
|
+
"lib/borg/borg_tasks.rake",
|
37
|
+
"lib/borg/borg_test_unit.rb",
|
38
|
+
"lib/borg/borg_worker.rb",
|
39
|
+
"lib/borg/railtie.rb"
|
40
|
+
]
|
41
|
+
s.homepage = %q{http://github.com/gnufied/borg}
|
42
|
+
s.licenses = ["MIT"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubygems_version = %q{1.3.7}
|
45
|
+
s.summary = %q{A distributed Test Suite runner for Rails, using Eventmachine and Redis}
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
|
53
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
55
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
56
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
59
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
60
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
61
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
62
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
63
|
+
end
|
64
|
+
else
|
65
|
+
s.add_dependency(%q<eventmachine>, [">= 0"])
|
66
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
67
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
68
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
69
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Borg
|
2
|
+
module AbstractAdapter
|
3
|
+
def load_environment(env_name)
|
4
|
+
puts "Loading Rails.."
|
5
|
+
ENV["RAILS_ENV"] = env_name
|
6
|
+
Rails.env = env_name
|
7
|
+
require(File.join(Rails.root, 'config', 'environment'))
|
8
|
+
$: << "#{Rails.root}/test"
|
9
|
+
$: << "#{Rails.root}/test/test_helpers"
|
10
|
+
require File.join(Rails.root, "test", "test_helper")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Free file descriptors and
|
14
|
+
# point them somewhere sensible
|
15
|
+
# STDOUT/STDERR should go to a logfile
|
16
|
+
def redirect_io(logfile_name)
|
17
|
+
begin
|
18
|
+
; STDIN.reopen "/dev/null";
|
19
|
+
rescue ::Exception;
|
20
|
+
end
|
21
|
+
|
22
|
+
if logfile_name
|
23
|
+
begin
|
24
|
+
STDOUT.reopen logfile_name, "a"
|
25
|
+
STDOUT.sync = true
|
26
|
+
rescue ::Exception
|
27
|
+
begin
|
28
|
+
; STDOUT.reopen "/dev/null";
|
29
|
+
rescue ::Exception;
|
30
|
+
end
|
31
|
+
end
|
32
|
+
else
|
33
|
+
begin
|
34
|
+
; STDOUT.reopen "/dev/null";
|
35
|
+
rescue ::Exception;
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
begin
|
40
|
+
; STDERR.reopen STDOUT;
|
41
|
+
rescue ::Exception;
|
42
|
+
end
|
43
|
+
STDERR.sync = true
|
44
|
+
end
|
45
|
+
|
46
|
+
def redirect_stdout
|
47
|
+
STDOUT.sync = true
|
48
|
+
begin
|
49
|
+
STDERR.reopen STDOUT;
|
50
|
+
rescue ::Exception;
|
51
|
+
end
|
52
|
+
STDERR.sync = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def try_migration_first(db_counter)
|
56
|
+
begin
|
57
|
+
db_config = get_connection_config(db_counter)
|
58
|
+
ActiveRecord::Base.establish_connection(db_config)
|
59
|
+
ActiveRecord::Base.connection()
|
60
|
+
migrate_db()
|
61
|
+
return true
|
62
|
+
rescue Exception => e
|
63
|
+
puts e.message
|
64
|
+
return false
|
65
|
+
rescue StandardError
|
66
|
+
puts $!.message
|
67
|
+
return false
|
68
|
+
rescue Mysql2::Error
|
69
|
+
puts $!.message
|
70
|
+
return false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def prepare_databse(db_counter)
|
75
|
+
create_db_using_raw_sql(db_counter)
|
76
|
+
try_migration_first(db_counter)
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_db_using_raw_sql(db_counter)
|
80
|
+
test_config = config['test']
|
81
|
+
sql_connection = Mysql2::Client.new(test_config.symbolize_keys)
|
82
|
+
db_config = get_connection_config(db_counter)
|
83
|
+
sql_connection.query("DROP DATABASE IF EXISTS #{db_config['database']}")
|
84
|
+
sql_connection.query("CREATE DATABASE #{db_config['database']}")
|
85
|
+
sql_connection.close()
|
86
|
+
end
|
87
|
+
|
88
|
+
def migrate_db
|
89
|
+
ENV["VERBOSE"] = "true"
|
90
|
+
Rake::Task["db:migrate"].invoke
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_connection_config(db_counter)
|
94
|
+
default_settings = config["test"].clone()
|
95
|
+
default_settings['database'] = "#{default_settings['database']}_#{db_counter}"
|
96
|
+
default_settings
|
97
|
+
end
|
98
|
+
|
99
|
+
def config
|
100
|
+
ActiveRecord::Base.configurations
|
101
|
+
end
|
102
|
+
|
103
|
+
def redis
|
104
|
+
Redis.new(:host => Borg::Config.redis_ip,:port => Borg::Config.redis_port)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_files_to_redis(files,key)
|
108
|
+
redis.del key
|
109
|
+
files.each { |x| redis.rpush(key, x.join(",")) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def remove_file_groups_from_redis(key,&block)
|
113
|
+
redis_has_files = true
|
114
|
+
@redis_connection = redis
|
115
|
+
all_status = []
|
116
|
+
|
117
|
+
loop do
|
118
|
+
local_pids = []
|
119
|
+
n.times do |index|
|
120
|
+
test_files = @redis_connection.rpop(key)
|
121
|
+
if(test_files)
|
122
|
+
local_pids << Process.fork { block.call(index,test_files) }
|
123
|
+
else
|
124
|
+
redis_has_files = false
|
125
|
+
break
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
Signal.trap 'SIGINT', lambda { local_pids.each { |p| Process.kill("KILL", p) }; exit 1 }
|
130
|
+
all_status += Process.waitall.map { |pid, status| status.exitstatus }
|
131
|
+
break unless redis_has_files
|
132
|
+
end #end of loop
|
133
|
+
|
134
|
+
raise "Error running #{key} tests" if (all_status.any? { |x| x != 0 })
|
135
|
+
|
136
|
+
end #end of method remove_file_groups_from_redis
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Borg
|
2
|
+
class CucumberRunner
|
3
|
+
include AbstractAdapter
|
4
|
+
|
5
|
+
def run(n = 3)
|
6
|
+
redirect_stdout()
|
7
|
+
load_environment('cucumber')
|
8
|
+
|
9
|
+
remove_file_groups_from_redis('cucumber') do |index,feature_files|
|
10
|
+
prepare_databse(index) unless try_migration_first(index)
|
11
|
+
full_feature_path = feature_files.split(',').map do |fl|
|
12
|
+
Rails.root.to_s + fl
|
13
|
+
end
|
14
|
+
args = %w(--format progress) + full_feature_path
|
15
|
+
failure = Cucumber::Cli::Main.execute(args)
|
16
|
+
raise "Cucumber failed" if failure
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_to_redis(worker_count)
|
22
|
+
feature_files = Dir["#{Rails.root}/features/**/*.feature"].map do |fl|
|
23
|
+
fl.gsub(/#{Rails.root}/,'')
|
24
|
+
end.sort.in_groups(worker_count, false)
|
25
|
+
add_files_to_redis(feature_files,'cucumber')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Borg
|
4
|
+
|
5
|
+
class Git
|
6
|
+
attr_accessor :status
|
7
|
+
def current_branch
|
8
|
+
cmd_output = `git symbolic-ref HEAD`
|
9
|
+
branch_name = cmd_output.strip.split("/")[-1]
|
10
|
+
branch_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(worker)
|
14
|
+
FileUtils.cd(Rails.root) do
|
15
|
+
#update_command = "git reset --hard HEAD && git fetch && git rebase origin/#{current_branch} && git submodule init && git submodule update && bundle install --local"
|
16
|
+
|
17
|
+
update_command = "bundle install --local"
|
18
|
+
puts "Update command is #{update_command}"
|
19
|
+
EM.popen(update_command,TestRunner) do |process|
|
20
|
+
process.worker = worker
|
21
|
+
process.runner_type = 'git'
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Borg
|
2
|
+
class Requestor < EM::Connection
|
3
|
+
include EM::P::ObjectProtocol
|
4
|
+
def self.make_request
|
5
|
+
EM.connect(Borg::Config.ip,Borg::Config.port,Requestor)
|
6
|
+
end
|
7
|
+
|
8
|
+
def connection_completed
|
9
|
+
@server_running = true
|
10
|
+
send_object(BuildRequester.new())
|
11
|
+
end
|
12
|
+
|
13
|
+
def receive_object(ruby_object)
|
14
|
+
case ruby_object
|
15
|
+
when BuildOutput
|
16
|
+
print ruby_object.data
|
17
|
+
when BuildStatus
|
18
|
+
stop_build(ruby_object)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def unbind
|
23
|
+
unless @server_running
|
24
|
+
puts "Error running server"
|
25
|
+
EM.stop()
|
26
|
+
else
|
27
|
+
EM.stop()
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop_build(ruby_object)
|
32
|
+
puts
|
33
|
+
if(ruby_object.exit_status == 0)
|
34
|
+
puts "Successfully ran all tests"
|
35
|
+
EM.stop()
|
36
|
+
else
|
37
|
+
abort("Error running tests")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Borg
|
2
|
+
class Server < EM::Connection
|
3
|
+
include EM::P::ObjectProtocol
|
4
|
+
@@workers = {}
|
5
|
+
@@requester = {}
|
6
|
+
|
7
|
+
@@status_count = 0
|
8
|
+
@@status_reports = []
|
9
|
+
attr_accessor :client_type
|
10
|
+
|
11
|
+
def receive_object(ruby_object)
|
12
|
+
case ruby_object
|
13
|
+
when BuildOutput
|
14
|
+
send_to_requester(ruby_object)
|
15
|
+
when BuildStatus
|
16
|
+
puts "Received object #{ruby_object.inspect}"
|
17
|
+
collect_status_response(ruby_object)
|
18
|
+
when WorkerConnected
|
19
|
+
@@workers[self.signature] = self
|
20
|
+
@client_type = :worker
|
21
|
+
when BuildRequester
|
22
|
+
@@requester[self.signature] = self
|
23
|
+
@client_type = :requestor
|
24
|
+
check_for_workers && add_tests_to_redis && start_build
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_for_workers
|
29
|
+
return true unless @@workers.empty?
|
30
|
+
send_error_to_requester("No worker found running")
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def send_error_to_requester(message)
|
35
|
+
send_to_requester(BuildOutput.new(message))
|
36
|
+
send_to_requester(BuildStatus.new(1))
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_tests_to_redis
|
40
|
+
begin
|
41
|
+
TestUnit.new().add_to_redis(@@workers.size * 3)
|
42
|
+
CucumberRunner.new().add_to_redis(@@workers.size * 3)
|
43
|
+
true
|
44
|
+
rescue
|
45
|
+
puts $!.message
|
46
|
+
puts $!.backtrace
|
47
|
+
send_error_to_requester("Error adding files to redis")
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def collect_status_response(ruby_object)
|
53
|
+
@@status_reports << ruby_object
|
54
|
+
@@status_count -= 1
|
55
|
+
puts "Status count is #{@@status_count}"
|
56
|
+
if(@@status_count == 0)
|
57
|
+
error_status = @@status_reports.any? {|x| x.exit_status != 0 }
|
58
|
+
@@status_reports = []
|
59
|
+
if(error_status)
|
60
|
+
send_to_requester(BuildStatus.new(1))
|
61
|
+
else
|
62
|
+
send_to_requester(BuildStatus.new(0))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def unbind
|
68
|
+
@@workers.delete(self.signature)
|
69
|
+
@@requester.delete(self.signature)
|
70
|
+
if(client_type == :requestor)
|
71
|
+
@@status_count = 0
|
72
|
+
@@status_reports = []
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def start_build
|
77
|
+
@@workers.each do |key,worker|
|
78
|
+
@@status_count += 1
|
79
|
+
worker.send_object(StartBuild.new())
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_to_requester(ruby_object)
|
84
|
+
@@requester.each do |key,requester|
|
85
|
+
requester.send_object(ruby_object)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
namespace :borg do
|
3
|
+
[:unit, :functional].each do |t|
|
4
|
+
type = t.to_s.sub(/s$/, '')
|
5
|
+
|
6
|
+
desc "Run #{type} tests"
|
7
|
+
task t, :count do |t, args|
|
8
|
+
Borg.load_environment
|
9
|
+
size = args[:count] ? args[:count].to_i : 3
|
10
|
+
#Borg.prepare_all_databases(size)
|
11
|
+
puts "Running #{type} tests using #{size} processes"
|
12
|
+
Borg.run_tests type, size
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Request server to run test"
|
17
|
+
task :build => :environment do
|
18
|
+
# Borg::TestUnit.new().add_to_redis
|
19
|
+
# Borg::CucumberRunner.new().add_to_redis
|
20
|
+
EM.run {
|
21
|
+
Borg::Requestor.make_request
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Start server"
|
26
|
+
task :start_server => :environment do
|
27
|
+
EM.run {
|
28
|
+
puts "Ip is #{Borg::Config.ip} and #{Borg::Config.port}"
|
29
|
+
EM.start_server(Borg::Config.ip,Borg::Config.port,Borg::Server)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Start Client"
|
34
|
+
task :start_client => :environment do
|
35
|
+
EM.run {
|
36
|
+
EM.connect(Borg::Config.ip,Borg::Config.port,Borg::Worker)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Run unit and functional test"
|
41
|
+
task :test do
|
42
|
+
Borg::TestUnit.new().run()
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Run cucumber tests"
|
46
|
+
task :cucumber do
|
47
|
+
Borg::CucumberRunner.new().run()
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# desc "Run redis tests"
|
52
|
+
# task :redis_test, :count do |t,args|
|
53
|
+
# Borg.load_environment('test')
|
54
|
+
# size = args[:count] ? args[:count].to_i : 3
|
55
|
+
# puts "Running tests using #{size} processes"
|
56
|
+
# Borg.run_redis_test(size)
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# desc "Run cucumber parallel test"
|
60
|
+
# task :cucumber, :count do |t,args|
|
61
|
+
# Borg.load_environment('cucumber')
|
62
|
+
# size = args[:count] ? args[:count].to_i : 3
|
63
|
+
# puts "Running Cucumber tests using #{size} processes"
|
64
|
+
# puts "Using the default profile..."
|
65
|
+
# Borg.run_cucumber(size)
|
66
|
+
# end
|
67
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Borg
|
2
|
+
class TestUnit
|
3
|
+
include AbstractAdapter
|
4
|
+
|
5
|
+
def run(n = 3)
|
6
|
+
redirect_stdout()
|
7
|
+
load_environment('test')
|
8
|
+
remove_file_groups_from_redis('tests') do |index,test_files|
|
9
|
+
prepare_databse(index) unless try_migration_first(index)
|
10
|
+
test_files.split(',').each do |fl|
|
11
|
+
load(Rails.root.to_s + fl)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_to_redis(worker_count)
|
17
|
+
test_files = (Dir["#{Rails.root}/test/unit/**/**_test.rb"] + Dir["#{Rails.root}/test/functional/**/**_test.rb"]).map do |fl|
|
18
|
+
fl.gsub(/#{Rails.root}/,'')
|
19
|
+
end.sort.in_groups(worker_count, false)
|
20
|
+
add_files_to_redis(test_files,'tests')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Borg
|
2
|
+
class Worker < EM::Connection
|
3
|
+
include EM::P::ObjectProtocol
|
4
|
+
@@status_reports = []
|
5
|
+
|
6
|
+
def receive_object(ruby_object)
|
7
|
+
case ruby_object
|
8
|
+
when StartBuild
|
9
|
+
update_code
|
10
|
+
when StartTest
|
11
|
+
start_test
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection_completed
|
16
|
+
send_object(WorkerConnected.new(self.signature))
|
17
|
+
end
|
18
|
+
|
19
|
+
def unbind
|
20
|
+
EM.add_timer(3) {
|
21
|
+
reconnect(Borg::Config.ip,Borg::Config.port)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_code
|
26
|
+
source_control = Borg::Git.new()
|
27
|
+
source_control.update(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def redis
|
31
|
+
Redis.new(:host => Borg::Config.redis_ip,:port => Borg::Config.redis_port)
|
32
|
+
end
|
33
|
+
|
34
|
+
def code_updated(last_status)
|
35
|
+
if(last_status.exit_status == 0)
|
36
|
+
start_test
|
37
|
+
else
|
38
|
+
puts "sending error report"
|
39
|
+
send_object(BuildStatus.new(1))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def start_test
|
44
|
+
if(redis.llen("tests") > 0)
|
45
|
+
EM.popen("rake tickle:test RAILS_ENV=test", TestRunner) do |process|
|
46
|
+
process.worker = self
|
47
|
+
process.runner_type = 'unit'
|
48
|
+
end
|
49
|
+
else
|
50
|
+
start_cucumber(BuildStatus.new(0))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def start_cucumber(last_status)
|
55
|
+
@@status_reports << last_status
|
56
|
+
if(redis.llen("cucumber") > 0)
|
57
|
+
EM.popen("rake tickle:cucumber RAILS_ENV=cucumber",TestRunner) do |process|
|
58
|
+
process.worker = self
|
59
|
+
process.runner_type = 'cucumber'
|
60
|
+
end
|
61
|
+
else
|
62
|
+
send_final_report(BuildStatus.new(0))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def send_final_report(last_status)
|
67
|
+
@@status_reports << last_status
|
68
|
+
p @@status_reports
|
69
|
+
error_flag = @@status_reports.any? {|x| x.exit_status != 0}
|
70
|
+
|
71
|
+
if(error_flag)
|
72
|
+
send_object(BuildStatus.new(1))
|
73
|
+
else
|
74
|
+
send_object(BuildStatus.new(0))
|
75
|
+
end
|
76
|
+
@@status_reports = []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class TestRunner < EM::Connection
|
81
|
+
attr_accessor :worker
|
82
|
+
attr_accessor :runner_type
|
83
|
+
|
84
|
+
include EM::P::ObjectProtocol
|
85
|
+
def receive_data(data)
|
86
|
+
worker.send_object(BuildOutput.new(data))
|
87
|
+
end
|
88
|
+
|
89
|
+
def unbind
|
90
|
+
puts "Sending the status thingy"
|
91
|
+
case runner_type
|
92
|
+
when 'unit'
|
93
|
+
worker.start_cucumber(BuildStatus.new(get_status.exitstatus))
|
94
|
+
when 'git'
|
95
|
+
worker.code_updated(BuildStatus.new(get_status.exitstatus))
|
96
|
+
else
|
97
|
+
worker.send_final_report(BuildStatus.new(get_status.exitstatus))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
data/lib/borg/railtie.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require "eventmachine"
|
3
|
+
require "redis"
|
4
|
+
require File.join(File.dirname(__FILE__),'borg_abstract_adapter')
|
5
|
+
require File.join(File.dirname(__FILE__),'borg_config')
|
6
|
+
require File.join(File.dirname(__FILE__),'borg_cucumber')
|
7
|
+
require File.join(File.dirname(__FILE__),'borg_git')
|
8
|
+
require File.join(File.dirname(__FILE__),'borg_messages')
|
9
|
+
|
10
|
+
require File.join(File.dirname(__FILE__),'borg_requestor')
|
11
|
+
require File.join(File.dirname(__FILE__),'borg_server')
|
12
|
+
|
13
|
+
require File.join(File.dirname(__FILE__),'borg_test_unit')
|
14
|
+
require File.join(File.dirname(__FILE__),'borg_worker')
|
15
|
+
|
16
|
+
|
17
|
+
module Borg
|
18
|
+
class Railtie < Rails::Railtie
|
19
|
+
rake_tasks do
|
20
|
+
load File.join(File.dirname(__FILE__),'borg_tasks.rake')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/borg.rb
ADDED
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: borg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Hemant Kumar
|
14
|
+
- Karunakar
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-02-07 00:00:00 +05:30
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
prerelease: false
|
24
|
+
type: :runtime
|
25
|
+
name: eventmachine
|
26
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
hash: 3
|
32
|
+
segments:
|
33
|
+
- 0
|
34
|
+
version: "0"
|
35
|
+
requirement: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
prerelease: false
|
38
|
+
type: :runtime
|
39
|
+
name: redis
|
40
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
requirement: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
prerelease: false
|
52
|
+
type: :development
|
53
|
+
name: bundler
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 23
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 0
|
63
|
+
- 0
|
64
|
+
version: 1.0.0
|
65
|
+
requirement: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
prerelease: false
|
68
|
+
type: :development
|
69
|
+
name: jeweler
|
70
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 7
|
76
|
+
segments:
|
77
|
+
- 1
|
78
|
+
- 5
|
79
|
+
- 2
|
80
|
+
version: 1.5.2
|
81
|
+
requirement: *id004
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
prerelease: false
|
84
|
+
type: :development
|
85
|
+
name: rspec
|
86
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirement: *id005
|
96
|
+
description: A distributed Test Suite runner for Rails, using Eventmachine and Redis
|
97
|
+
email: hkumar@crri.co.in
|
98
|
+
executables: []
|
99
|
+
|
100
|
+
extensions: []
|
101
|
+
|
102
|
+
extra_rdoc_files:
|
103
|
+
- LICENSE.txt
|
104
|
+
- README.rdoc
|
105
|
+
files:
|
106
|
+
- .document
|
107
|
+
- Gemfile
|
108
|
+
- Gemfile.lock
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.rdoc
|
111
|
+
- Rakefile
|
112
|
+
- VERSION
|
113
|
+
- borg.gemspec
|
114
|
+
- lib/borg.rb
|
115
|
+
- lib/borg/borg_abstract_adapter.rb
|
116
|
+
- lib/borg/borg_config.rb
|
117
|
+
- lib/borg/borg_cucumber.rb
|
118
|
+
- lib/borg/borg_git.rb
|
119
|
+
- lib/borg/borg_messages.rb
|
120
|
+
- lib/borg/borg_requestor.rb
|
121
|
+
- lib/borg/borg_server.rb
|
122
|
+
- lib/borg/borg_tasks.rake
|
123
|
+
- lib/borg/borg_test_unit.rb
|
124
|
+
- lib/borg/borg_worker.rb
|
125
|
+
- lib/borg/railtie.rb
|
126
|
+
has_rdoc: true
|
127
|
+
homepage: http://github.com/gnufied/borg
|
128
|
+
licenses:
|
129
|
+
- MIT
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
hash: 3
|
141
|
+
segments:
|
142
|
+
- 0
|
143
|
+
version: "0"
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
hash: 3
|
150
|
+
segments:
|
151
|
+
- 0
|
152
|
+
version: "0"
|
153
|
+
requirements: []
|
154
|
+
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 1.3.7
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: A distributed Test Suite runner for Rails, using Eventmachine and Redis
|
160
|
+
test_files: []
|
161
|
+
|