testbot 0.4.7 → 0.4.8
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/CHANGELOG +4 -0
- data/README.markdown +1 -1
- data/lib/runner/job.rb +1 -1
- data/lib/server/build.rb +14 -10
- data/lib/server/job.rb +23 -24
- data/lib/server/memory_model.rb +87 -0
- data/lib/server/runner.rb +13 -8
- data/lib/server/server.rb +11 -10
- data/lib/shared/testbot.rb +1 -1
- data/testbot.gemspec +1 -5
- metadata +11 -43
- data/lib/server/db.rb +0 -49
data/CHANGELOG
CHANGED
data/README.markdown
CHANGED
@@ -69,7 +69,7 @@ Using testbot with Rails 3:
|
|
69
69
|
|
70
70
|
Using testbot with Rails 2:
|
71
71
|
|
72
|
-
ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.4.
|
72
|
+
ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.4.8'
|
73
73
|
script/generate testbot --connect 192.168.0.100
|
74
74
|
|
75
75
|
rake testbot:spec (or :test, :features)
|
data/lib/runner/job.rb
CHANGED
data/lib/server/build.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Testbot::Server
|
2
2
|
|
3
|
-
class Build <
|
3
|
+
class Build < MemoryModel
|
4
|
+
|
5
|
+
def initialize(hash)
|
6
|
+
super({ :success => true, :done => false, :results => '' }.merge(hash))
|
7
|
+
end
|
4
8
|
|
5
9
|
def self.create_and_build_jobs(hash)
|
6
10
|
hash["jruby"] = (hash["jruby"] == "true") ? 1 : 0
|
@@ -10,21 +14,21 @@ module Testbot::Server
|
|
10
14
|
end
|
11
15
|
|
12
16
|
def create_jobs!(available_runner_usage)
|
13
|
-
groups = Group.build(self
|
14
|
-
Runner.total_instances.to_f * (available_runner_usage.to_i / 100.0), self
|
17
|
+
groups = Group.build(self.files.split, self.sizes.split.map { |size| size.to_i },
|
18
|
+
Runner.total_instances.to_f * (available_runner_usage.to_i / 100.0), self.type)
|
15
19
|
groups.each do |group|
|
16
20
|
Job.create(:files => group.join(' '),
|
17
|
-
:root => self
|
18
|
-
:project => self
|
19
|
-
:type => self
|
20
|
-
:requester_mac => self
|
21
|
-
:
|
22
|
-
:jruby => self
|
21
|
+
:root => self.root,
|
22
|
+
:project => self.project,
|
23
|
+
:type => self.type,
|
24
|
+
:requester_mac => self.requester_mac,
|
25
|
+
:build => self,
|
26
|
+
:jruby => self.jruby)
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
26
30
|
def destroy
|
27
|
-
Job.
|
31
|
+
Job.all.find_all { |j| j.build == self }.each { |job| job.destroy }
|
28
32
|
super
|
29
33
|
end
|
30
34
|
|
data/lib/server/job.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'db.rb'))
|
2
|
-
|
3
1
|
module Testbot::Server
|
4
2
|
|
5
|
-
class Job <
|
3
|
+
class Job < MemoryModel
|
4
|
+
|
5
|
+
attribute :success, :boolean
|
6
|
+
|
6
7
|
def update(hash)
|
7
8
|
super(hash)
|
8
|
-
if build
|
9
|
-
done = Job.
|
10
|
-
build.update(:results => build
|
11
|
-
|
9
|
+
if self.build
|
10
|
+
done = !Job.all.find { |j| !j.result && j.build == self.build }
|
11
|
+
self.build.update(:results => build.results.to_s + self.result.to_s,
|
12
|
+
:done => done)
|
12
13
|
|
13
|
-
build_broken_by_job = (
|
14
|
-
build.update(:success => false) if build_broken_by_job
|
14
|
+
build_broken_by_job = (!self.success && build.success)
|
15
|
+
self.build.update(:success => false) if build_broken_by_job
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
@@ -19,29 +20,27 @@ module Testbot::Server
|
|
19
20
|
clean_params = params.reject { |k, v| [ "requester_mac", "no_jruby" ].include?(k) }
|
20
21
|
runner = Runner.record! clean_params.merge({ :ip => remove_addr, :last_seen_at => Time.now })
|
21
22
|
return unless Server.valid_version?(params[:version])
|
22
|
-
[
|
23
|
+
[ next_job(params["requester_mac"], params["no_jruby"]), runner ]
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
26
27
|
|
27
|
-
def self.
|
28
|
+
def self.next_job(requester_mac, no_jruby)
|
28
29
|
release_jobs_taken_by_missing_runners!
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
query.filter(filters.join(' AND '))
|
37
|
-
end
|
30
|
+
jobs = Job.all.find_all { |j|
|
31
|
+
!j.taken_at &&
|
32
|
+
(requester_mac ? j.requester_mac == requester_mac : true) &&
|
33
|
+
(no_jruby ? j.jruby != 1 : true)
|
34
|
+
}
|
35
|
+
|
36
|
+
jobs[rand(jobs.size)]
|
38
37
|
end
|
39
38
|
|
40
39
|
def self.release_jobs_taken_by_missing_runners!
|
41
|
-
missing_runners = Runner.
|
42
|
-
missing_runners.each { |
|
43
|
-
Job.
|
44
|
-
}
|
40
|
+
missing_runners = Runner.all.find_all { |r| r.last_seen_at < (Time.now - Runner.timeout) }
|
41
|
+
missing_runners.each { |runner|
|
42
|
+
Job.all.find_all { |job| job.taken_by == runner }.each { |job| job.update(:taken_at => nil) }
|
43
|
+
}
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class MemoryModel < OpenStruct
|
2
|
+
|
3
|
+
@@db = {}
|
4
|
+
@@types = {}
|
5
|
+
|
6
|
+
def initialize(hash)
|
7
|
+
@@types[self.class] ||= {}
|
8
|
+
hash = resolve_types(symbolize_keys(hash))
|
9
|
+
super(hash)
|
10
|
+
end
|
11
|
+
|
12
|
+
def id
|
13
|
+
object_id
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
@table[:type]
|
18
|
+
end
|
19
|
+
|
20
|
+
def update(hash)
|
21
|
+
@table.merge!(resolve_types(symbolize_keys(hash)))
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy
|
26
|
+
self.class.all.delete_if { |b| b.id == id }
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find(id)
|
30
|
+
all.find { |r| r.id == id.to_i }
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.create(hash = {})
|
34
|
+
all << new(hash)
|
35
|
+
all[-1]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.all
|
39
|
+
@@db[self] ||= []
|
40
|
+
@@db[self]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.first
|
44
|
+
all.first
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.delete_all
|
48
|
+
all.clear
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.count
|
52
|
+
all.size
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.attribute(attribute, type)
|
56
|
+
@@types[self] ||= {}
|
57
|
+
@@types[self][attribute] = type
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def resolve_types(hash)
|
63
|
+
hash.each { |attribute, value|
|
64
|
+
case @@types[self.class][attribute]
|
65
|
+
when :integer
|
66
|
+
hash[attribute] = value.to_i
|
67
|
+
when :boolean
|
68
|
+
if value == "true"
|
69
|
+
hash[attribute] = true
|
70
|
+
elsif value == "false"
|
71
|
+
hash[attribute] = false
|
72
|
+
elsif value != true && value != false
|
73
|
+
hash[attribute] = nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
hash
|
78
|
+
end
|
79
|
+
|
80
|
+
def symbolize_keys(hash)
|
81
|
+
h = {}
|
82
|
+
hash.each { |k, v| h[k.to_sym] = v }
|
83
|
+
h
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
data/lib/server/runner.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'db.rb'))
|
2
|
-
|
3
1
|
module Testbot::Server
|
4
2
|
|
5
|
-
class Runner <
|
3
|
+
class Runner < MemoryModel
|
4
|
+
|
5
|
+
attribute :idle_instances, :integer
|
6
|
+
attribute :max_instances, :integer
|
6
7
|
|
7
8
|
def self.record!(hash)
|
8
9
|
create_or_update_by_mac!(hash)
|
9
10
|
end
|
10
11
|
|
11
12
|
def self.create_or_update_by_mac!(hash)
|
12
|
-
if
|
13
|
+
if runner = find_by_uid(hash[:uid])
|
13
14
|
runner.update hash
|
14
15
|
else
|
15
16
|
Runner.create hash
|
@@ -20,21 +21,25 @@ module Testbot::Server
|
|
20
21
|
10
|
21
22
|
end
|
22
23
|
|
24
|
+
def self.find_by_uid(uid)
|
25
|
+
all.find { |r| r.uid == uid }
|
26
|
+
end
|
27
|
+
|
23
28
|
def self.find_all_outdated
|
24
|
-
|
29
|
+
all.find_all { |r| r.version != Testbot.version }
|
25
30
|
end
|
26
31
|
|
27
32
|
def self.find_all_available
|
28
|
-
|
33
|
+
all.find_all { |r| r.version == Testbot.version && r.last_seen_at > (Time.now - Runner.timeout) }
|
29
34
|
end
|
30
35
|
|
31
36
|
def self.available_instances
|
32
|
-
find_all_available.inject(0) { |sum, r| r
|
37
|
+
find_all_available.inject(0) { |sum, r| r.idle_instances + sum }
|
33
38
|
end
|
34
39
|
|
35
40
|
def self.total_instances
|
36
41
|
return 1 if ENV['INTEGRATION_TEST']
|
37
|
-
find_all_available.inject(0) { |sum, r| r
|
42
|
+
find_all_available.inject(0) { |sum, r| r.max_instances + sum }
|
38
43
|
end
|
39
44
|
|
40
45
|
end
|
data/lib/server/server.rb
CHANGED
@@ -3,6 +3,7 @@ require 'sinatra'
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
5
|
require File.expand_path(File.join(File.dirname(__FILE__), '/../shared/testbot'))
|
6
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'memory_model.rb'))
|
6
7
|
require File.expand_path(File.join(File.dirname(__FILE__), 'job.rb'))
|
7
8
|
require File.expand_path(File.join(File.dirname(__FILE__), 'group.rb')) #unless defined?(Group)
|
8
9
|
require File.expand_path(File.join(File.dirname(__FILE__), 'runner.rb'))
|
@@ -23,36 +24,36 @@ module Testbot::Server
|
|
23
24
|
end
|
24
25
|
|
25
26
|
post '/builds' do
|
26
|
-
build = Build.create_and_build_jobs(params)
|
27
|
+
build = Build.create_and_build_jobs(params).id.to_s
|
27
28
|
end
|
28
29
|
|
29
30
|
get '/builds/:id' do
|
30
|
-
build = Build.find(
|
31
|
-
build.destroy if build
|
32
|
-
{ "done" => build
|
31
|
+
build = Build.find(params[:id])
|
32
|
+
build.destroy if build.done
|
33
|
+
{ "done" => build.done, "results" => build.results, "success" => build.success }.to_json
|
33
34
|
end
|
34
35
|
|
35
36
|
get '/jobs/next' do
|
36
37
|
next_job, runner = Job.next(params, @env['REMOTE_ADDR'])
|
37
38
|
if next_job
|
38
|
-
next_job.update(:taken_at => Time.now, :
|
39
|
-
[ next_job
|
39
|
+
next_job.update(:taken_at => Time.now, :taken_by => runner)
|
40
|
+
[ next_job.id, next_job.requester_mac, next_job.project, next_job.root, next_job.type, (next_job.jruby == 1 ? 'jruby' : 'ruby'), next_job.files ].join(',')
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
44
|
put '/jobs/:id' do
|
44
|
-
Job.find(
|
45
|
+
Job.find(params[:id]).update(:result => params[:result], :success => params[:success]); nil
|
45
46
|
end
|
46
47
|
|
47
48
|
get '/runners/ping' do
|
48
49
|
return unless Server.valid_version?(params[:version])
|
49
|
-
runner = Runner.
|
50
|
+
runner = Runner.find_by_uid(params[:uid])
|
50
51
|
runner.update(params.merge({ :last_seen_at => Time.now })) if runner
|
51
52
|
nil
|
52
53
|
end
|
53
54
|
|
54
55
|
get '/runners/outdated' do
|
55
|
-
Runner.find_all_outdated.map { |runner| [ runner
|
56
|
+
Runner.find_all_outdated.map { |runner| [ runner.ip, runner.hostname, runner.uid ].join(' ') }.join("\n").strip
|
56
57
|
end
|
57
58
|
|
58
59
|
get '/runners/available_instances' do
|
@@ -64,7 +65,7 @@ module Testbot::Server
|
|
64
65
|
end
|
65
66
|
|
66
67
|
get '/runners/available' do
|
67
|
-
Runner.find_all_available.map { |runner| [ runner
|
68
|
+
Runner.find_all_available.map { |runner| [ runner.ip, runner.hostname, runner.uid, runner.username, runner.idle_instances ].join(' ') }.join("\n").strip
|
68
69
|
end
|
69
70
|
|
70
71
|
get '/version' do
|
data/lib/shared/testbot.rb
CHANGED
@@ -7,7 +7,7 @@ module Testbot
|
|
7
7
|
|
8
8
|
# Don't forget to update readme and changelog
|
9
9
|
def self.version
|
10
|
-
version = "0.4.
|
10
|
+
version = "0.4.8"
|
11
11
|
dev_version_file = File.join(File.dirname(__FILE__), '..', '..', 'DEV_VERSION')
|
12
12
|
if File.exists?(dev_version_file)
|
13
13
|
version += File.read(dev_version_file)
|
data/testbot.gemspec
CHANGED
@@ -17,12 +17,8 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.add_dependency('httparty', '>= 0.6.1')
|
18
18
|
s.add_dependency('macaddr', '>= 1.0.0')
|
19
19
|
s.add_dependency('net-ssh', '>= 2.0.23')
|
20
|
-
s.add_dependency('
|
21
|
-
s.add_dependency('json', '>= 1.4.6')
|
20
|
+
s.add_dependency('json_pure', '>= 1.4.6')
|
22
21
|
s.add_dependency('daemons', '>= 1.0.10')
|
23
22
|
s.add_dependency('acts_as_rails3_generator')
|
24
|
-
|
25
|
-
# Could work with older versions, but not newer (when deploying on debian)
|
26
|
-
s.add_dependency('sqlite3-ruby', '= 1.2.5')
|
27
23
|
end
|
28
24
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: testbot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 8
|
10
|
+
version: 0.4.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Joakim Kolsj\xC3\xB6"
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-06 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -83,25 +83,9 @@ dependencies:
|
|
83
83
|
type: :runtime
|
84
84
|
version_requirements: *id004
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
|
-
name:
|
86
|
+
name: json_pure
|
87
87
|
prerelease: false
|
88
88
|
requirement: &id005 !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ">="
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
hash: 71
|
94
|
-
segments:
|
95
|
-
- 3
|
96
|
-
- 16
|
97
|
-
- 0
|
98
|
-
version: 3.16.0
|
99
|
-
type: :runtime
|
100
|
-
version_requirements: *id005
|
101
|
-
- !ruby/object:Gem::Dependency
|
102
|
-
name: json
|
103
|
-
prerelease: false
|
104
|
-
requirement: &id006 !ruby/object:Gem::Requirement
|
105
89
|
none: false
|
106
90
|
requirements:
|
107
91
|
- - ">="
|
@@ -113,11 +97,11 @@ dependencies:
|
|
113
97
|
- 6
|
114
98
|
version: 1.4.6
|
115
99
|
type: :runtime
|
116
|
-
version_requirements: *
|
100
|
+
version_requirements: *id005
|
117
101
|
- !ruby/object:Gem::Dependency
|
118
102
|
name: daemons
|
119
103
|
prerelease: false
|
120
|
-
requirement: &
|
104
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
121
105
|
none: false
|
122
106
|
requirements:
|
123
107
|
- - ">="
|
@@ -129,11 +113,11 @@ dependencies:
|
|
129
113
|
- 10
|
130
114
|
version: 1.0.10
|
131
115
|
type: :runtime
|
132
|
-
version_requirements: *
|
116
|
+
version_requirements: *id006
|
133
117
|
- !ruby/object:Gem::Dependency
|
134
118
|
name: acts_as_rails3_generator
|
135
119
|
prerelease: false
|
136
|
-
requirement: &
|
120
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
137
121
|
none: false
|
138
122
|
requirements:
|
139
123
|
- - ">="
|
@@ -143,23 +127,7 @@ dependencies:
|
|
143
127
|
- 0
|
144
128
|
version: "0"
|
145
129
|
type: :runtime
|
146
|
-
version_requirements: *
|
147
|
-
- !ruby/object:Gem::Dependency
|
148
|
-
name: sqlite3-ruby
|
149
|
-
prerelease: false
|
150
|
-
requirement: &id009 !ruby/object:Gem::Requirement
|
151
|
-
none: false
|
152
|
-
requirements:
|
153
|
-
- - "="
|
154
|
-
- !ruby/object:Gem::Version
|
155
|
-
hash: 21
|
156
|
-
segments:
|
157
|
-
- 1
|
158
|
-
- 2
|
159
|
-
- 5
|
160
|
-
version: 1.2.5
|
161
|
-
type: :runtime
|
162
|
-
version_requirements: *id009
|
130
|
+
version_requirements: *id007
|
163
131
|
description: Testbot is a test distribution tool that works with Rails, RSpec, Test::Unit and Cucumber.
|
164
132
|
email:
|
165
133
|
- joakim.kolsjo@gmail.com
|
@@ -178,9 +146,9 @@ files:
|
|
178
146
|
- lib/runner/job.rb
|
179
147
|
- lib/runner/runner.rb
|
180
148
|
- lib/server/build.rb
|
181
|
-
- lib/server/db.rb
|
182
149
|
- lib/server/group.rb
|
183
150
|
- lib/server/job.rb
|
151
|
+
- lib/server/memory_model.rb
|
184
152
|
- lib/server/runner.rb
|
185
153
|
- lib/server/server.rb
|
186
154
|
- lib/shared/adapters/adapter.rb
|
data/lib/server/db.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'sequel'
|
2
|
-
|
3
|
-
module Testbot::Server
|
4
|
-
|
5
|
-
DB = Sequel.sqlite
|
6
|
-
|
7
|
-
DB.create_table :builds do
|
8
|
-
primary_key :id
|
9
|
-
String :files
|
10
|
-
String :sizes
|
11
|
-
String :results, :default => ''
|
12
|
-
String :root
|
13
|
-
String :project
|
14
|
-
String :type
|
15
|
-
String :requester_mac
|
16
|
-
Integer :jruby
|
17
|
-
Boolean :success, :default => true
|
18
|
-
Boolean :done, :default => false
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
DB.create_table :jobs do
|
23
|
-
primary_key :id
|
24
|
-
String :files
|
25
|
-
String :result
|
26
|
-
String :root
|
27
|
-
String :project
|
28
|
-
String :type
|
29
|
-
String :requester_mac
|
30
|
-
Integer :jruby
|
31
|
-
Integer :build_id
|
32
|
-
Integer :taken_by_id
|
33
|
-
Boolean :success
|
34
|
-
Datetime :taken_at, :default => nil
|
35
|
-
end
|
36
|
-
|
37
|
-
DB.create_table :runners do
|
38
|
-
primary_key :id
|
39
|
-
String :ip
|
40
|
-
String :hostname
|
41
|
-
String :uid
|
42
|
-
String :username
|
43
|
-
String :version
|
44
|
-
Integer :idle_instances
|
45
|
-
Integer :max_instances
|
46
|
-
Datetime :last_seen_at
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|