testbot_instructure 0.7.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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG +264 -0
  4. data/Gemfile +3 -0
  5. data/README.markdown +141 -0
  6. data/Rakefile +35 -0
  7. data/bin/testbot +59 -0
  8. data/lib/generators/testbot/templates/testbot.rake.erb +35 -0
  9. data/lib/generators/testbot/templates/testbot.yml.erb +45 -0
  10. data/lib/generators/testbot/testbot_generator.rb +19 -0
  11. data/lib/railtie.rb +16 -0
  12. data/lib/requester/requester.rb +171 -0
  13. data/lib/runner/job.rb +112 -0
  14. data/lib/runner/runner.rb +222 -0
  15. data/lib/runner/safe_result_text.rb +29 -0
  16. data/lib/server/build.rb +36 -0
  17. data/lib/server/group.rb +48 -0
  18. data/lib/server/job.rb +64 -0
  19. data/lib/server/memory_model.rb +91 -0
  20. data/lib/server/runner.rb +47 -0
  21. data/lib/server/server.rb +103 -0
  22. data/lib/server/status/javascripts/jquery-1.4.4.min.js +167 -0
  23. data/lib/server/status/status.html +48 -0
  24. data/lib/server/status/stylesheets/status.css +14 -0
  25. data/lib/shared/adapters/adapter.rb +27 -0
  26. data/lib/shared/adapters/cucumber_adapter.rb +91 -0
  27. data/lib/shared/adapters/helpers/ruby_env.rb +47 -0
  28. data/lib/shared/adapters/rspec2_adapter.rb +61 -0
  29. data/lib/shared/adapters/rspec_adapter.rb +79 -0
  30. data/lib/shared/adapters/test_unit_adapter.rb +44 -0
  31. data/lib/shared/color.rb +16 -0
  32. data/lib/shared/simple_daemonize.rb +25 -0
  33. data/lib/shared/ssh_tunnel.rb +36 -0
  34. data/lib/shared/testbot.rb +132 -0
  35. data/lib/shared/version.rb +12 -0
  36. data/lib/tasks/testbot.rake +30 -0
  37. data/lib/testbot.rb +2 -0
  38. data/test/fixtures/local/Rakefile +7 -0
  39. data/test/fixtures/local/config/testbot.yml +5 -0
  40. data/test/fixtures/local/log/test.log +0 -0
  41. data/test/fixtures/local/script/spec +2 -0
  42. data/test/fixtures/local/spec/models/car_spec.rb +0 -0
  43. data/test/fixtures/local/spec/models/house_spec.rb +0 -0
  44. data/test/fixtures/local/spec/spec.opts +0 -0
  45. data/test/fixtures/local/tmp/restart.txt +0 -0
  46. data/test/integration_test.rb +55 -0
  47. data/test/requester/requester_test.rb +407 -0
  48. data/test/requester/testbot.yml +7 -0
  49. data/test/requester/testbot_with_erb.yml +2 -0
  50. data/test/runner/job_test.rb +94 -0
  51. data/test/runner/safe_result_text_test.rb +20 -0
  52. data/test/server/group_test.rb +43 -0
  53. data/test/server/server_test.rb +511 -0
  54. data/test/shared/adapters/adapter_test.rb +22 -0
  55. data/test/shared/adapters/cucumber_adapter_test.rb +72 -0
  56. data/test/shared/adapters/helpers/ruby_env_test.rb +108 -0
  57. data/test/shared/adapters/rspec_adapter_test.rb +109 -0
  58. data/test/shared/testbot_test.rb +185 -0
  59. data/testbot.gemspec +34 -0
  60. metadata +313 -0
@@ -0,0 +1,511 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/server/server'))
2
+ require 'test/unit'
3
+ require 'rack/test'
4
+ require 'shoulda'
5
+ require 'flexmock/test_unit'
6
+
7
+ set :environment, :test
8
+
9
+ module Testbot::Server
10
+
11
+ class ServerTest < Test::Unit::TestCase
12
+ include Rack::Test::Methods
13
+
14
+ def setup
15
+ Job.delete_all
16
+ Runner.delete_all
17
+ Build.delete_all
18
+ end
19
+
20
+ def app
21
+ Sinatra::Application
22
+ end
23
+
24
+ context "POST /builds" do
25
+
26
+ should "create a build and return its id" do
27
+ flexmock(Runner).should_receive(:total_instances).and_return(2)
28
+ post '/builds', :files => 'spec/models/car_spec.rb spec/models/house_spec.rb', :root => 'server:/path/to/project', :type => 'spec', :available_runner_usage => "100%", :project => 'things', :sizes => "10 20", :jruby => false
29
+
30
+ first_build = Build.all.first
31
+ assert last_response.ok?
32
+
33
+ assert_equal first_build.id.to_s, last_response.body
34
+ assert_equal 'spec/models/car_spec.rb spec/models/house_spec.rb', first_build.files
35
+ assert_equal '10 20', first_build.sizes
36
+ assert_equal 'server:/path/to/project', first_build.root
37
+ assert_equal 'spec', first_build.type
38
+ assert_equal 'things', first_build.project
39
+ assert_equal 0, first_build.jruby
40
+ assert_equal '', first_build.results
41
+ assert_equal true, first_build.success
42
+ end
43
+
44
+ should "create jobs from the build based on the number of total instances" do
45
+ flexmock(Runner).should_receive(:total_instances).and_return(2)
46
+ flexmock(Group).should_receive(:build).with(["spec/models/car_spec.rb", "spec/models/car2_spec.rb", "spec/models/house_spec.rb", "spec/models/house2_spec.rb"], [ 1, 1, 1, 1 ], 2, 'spec').once.and_return([
47
+ ["spec/models/car_spec.rb", "spec/models/car2_spec.rb"],
48
+ ["spec/models/house_spec.rb", "spec/models/house2_spec.rb"]
49
+ ])
50
+
51
+ post '/builds', :files => 'spec/models/car_spec.rb spec/models/car2_spec.rb spec/models/house_spec.rb spec/models/house2_spec.rb', :root => 'server:/path/to/project', :type => 'spec', :available_runner_usage => "100%", :project => 'things', :sizes => "1 1 1 1", :jruby => true
52
+
53
+ assert_equal 2, Job.count
54
+ first_job, last_job = Job.all
55
+ assert_equal 'spec/models/car_spec.rb spec/models/car2_spec.rb', first_job.files
56
+ assert_equal 'spec/models/house_spec.rb spec/models/house2_spec.rb', last_job.files
57
+
58
+ assert_equal 'server:/path/to/project', first_job.root
59
+ assert_equal 'spec', first_job.type
60
+ assert_equal 'things', first_job.project
61
+ assert_equal 1, first_job.jruby
62
+ assert_equal Build.all.first, first_job.build
63
+ end
64
+
65
+ should "return a 503 error if there are no known runners" do
66
+ flexmock(Runner).should_receive(:total_instances).and_return(0)
67
+ post '/builds', :files => 'spec/models/car_spec.rb spec/models/car2_spec.rb spec/models/house_spec.rb spec/models/house2_spec.rb', :root => 'server:/path/to/project', :type => 'spec', :available_runner_usage => "100%", :project => 'things', :sizes => "1 1 1 1", :jruby => true
68
+ assert_equal 0, Job.count
69
+ assert_equal 503, last_response.status
70
+ assert_equal "No runners available", last_response.body
71
+ end
72
+
73
+ should "only use resources according to available_runner_usage" do
74
+ flexmock(Runner).should_receive(:total_instances).and_return(4)
75
+ flexmock(Group).should_receive(:build).with(["spec/models/car_spec.rb", "spec/models/car2_spec.rb", "spec/models/house_spec.rb", "spec/models/house2_spec.rb"], [ 1, 1, 1, 1 ], 2, 'spec').and_return([])
76
+ post '/builds', :files => 'spec/models/car_spec.rb spec/models/car2_spec.rb spec/models/house_spec.rb spec/models/house2_spec.rb', :root => 'server:/path/to/project', :type => 'spec', :sizes => "1 1 1 1", :available_runner_usage => "50%"
77
+ end
78
+
79
+ end
80
+
81
+ context "GET /builds/:id" do
82
+
83
+ should 'return the build status' do
84
+ build = Build.create(:done => false, :results => "testbot5\n..........\ncompleted", :success => false)
85
+ get "/builds/#{build.id}"
86
+ assert_equal true, last_response.ok?
87
+ assert_equal ({ "done" => false, "results" => "testbot5\n..........\ncompleted", "success" => false }),
88
+ JSON.parse(last_response.body)
89
+ end
90
+
91
+ should 'remove a build that is done' do
92
+ build = Build.create(:done => true)
93
+ get "/builds/#{build.id}"
94
+ assert_equal true, JSON.parse(last_response.body)['done']
95
+ assert_equal 0, Build.count
96
+ end
97
+
98
+ should 'remove all related jobs of a build that is done' do
99
+ build = Build.create(:done => true)
100
+ related_job = Job.create(:build => build)
101
+ other_job = Job.create(:build => nil)
102
+ get "/builds/#{build.id}"
103
+ assert !Job.find(related_job.id)
104
+ assert Job.find(other_job.id)
105
+ end
106
+
107
+ end
108
+
109
+ context "GET /jobs/next" do
110
+
111
+ should "be able to return a job and mark it as taken" do
112
+ build = Build.create
113
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :root => 'server:/project', :type => 'spec', :build => build, :project => 'things', :jruby => 1
114
+
115
+ get '/jobs/next', :version => Testbot.version
116
+ assert last_response.ok?
117
+
118
+ assert_equal [ job1.id, build.id, "things", "server:/project", "spec", "jruby", "spec/models/car_spec.rb" ].join(','), last_response.body
119
+ assert job1.taken_at != nil
120
+ end
121
+
122
+ should "not return a job that has already been taken" do
123
+ build = Build.create
124
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now, :type => 'spec', :build => build
125
+ job2 = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build, :project => 'things', :jruby => 0
126
+ get '/jobs/next', :version => Testbot.version
127
+ assert last_response.ok?
128
+ assert_equal [ job2.id, build.id, "things", "server:/project", "spec", "ruby", "spec/models/house_spec.rb" ].join(','), last_response.body
129
+ assert job2.taken_at != nil
130
+ end
131
+
132
+ should "not return a job if there isnt any" do
133
+ get '/jobs/next', :version => Testbot.version
134
+ assert last_response.ok?
135
+ assert_equal '', last_response.body
136
+ end
137
+
138
+ should "save which runner takes a job" do
139
+ job = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => Build.create
140
+ get '/jobs/next', :version => Testbot.version
141
+ assert_equal Runner.first, job.taken_by
142
+ end
143
+
144
+ should "save information about the runners" do
145
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini.local', :uid => "00:01:...", :idle_instances => 2, :max_instances => 4
146
+ runner = Runner.first
147
+ assert_equal Testbot.version, runner.version
148
+ assert_equal '127.0.0.1', runner.ip
149
+ assert_equal 'macmini.local', runner.hostname
150
+ assert_equal '00:01:...', runner.uid
151
+ assert_equal 2, runner.idle_instances
152
+ assert_equal 4, runner.max_instances
153
+ assert (Time.now - 5) < runner.last_seen_at
154
+ assert (Time.now + 5) > runner.last_seen_at
155
+ end
156
+
157
+ should "only create one record for the same mac" do
158
+ get '/jobs/next', :version => Testbot.version, :uid => "00:01:..."
159
+ get '/jobs/next', :version => Testbot.version, :uid => "00:01:..."
160
+ assert_equal 1, Runner.count
161
+ end
162
+
163
+ should "not return anything to outdated clients" do
164
+ Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project'
165
+ get '/jobs/next', :version => "1", :uid => "00:..."
166
+ assert last_response.ok?
167
+ assert_equal '', last_response.body
168
+ end
169
+
170
+ should "only give jobs from the same source to a runner" do
171
+ build = Build.create
172
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :type => 'spec', :build => build
173
+ get '/jobs/next', :version => Testbot.version, :uid => "00:...", :build_id => build.id
174
+
175
+ # Creating the second job here because of the random lookup.
176
+ job2 = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build
177
+ get '/jobs/next', :version => Testbot.version, :uid => "00:...", :build_id => build.id + 1
178
+
179
+ assert last_response.ok?
180
+ assert_equal '', last_response.body
181
+ end
182
+
183
+ should "not give more jruby jobs to an instance that can't take more" do
184
+ build = Build.create
185
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :type => 'spec', :jruby => 1, :build => build
186
+ get '/jobs/next', :version => Testbot.version, :uid => "00:..."
187
+
188
+ # Creating the second job here because of the random lookup.
189
+ job2 = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :jruby => 1, :build => build
190
+ get '/jobs/next', :version => Testbot.version, :uid => "00:...", :no_jruby => "true"
191
+
192
+ assert last_response.ok?
193
+ assert_equal '', last_response.body
194
+ end
195
+
196
+ should "still return other jobs when the runner cant take more jruby jobs" do
197
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :type => 'spec', :jruby => 1, :build => Build.create
198
+ get '/jobs/next', :version => Testbot.version, :uid => "00:..."
199
+
200
+ # Creating the second job here because of the random lookup.
201
+ job2 = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :jruby => 0, :build => Build.create
202
+ get '/jobs/next', :version => Testbot.version, :uid => "00:...", :no_jruby => "true"
203
+
204
+ assert last_response.ok?
205
+ assert_equal job2.id.to_s, last_response.body.split(',')[0]
206
+ end
207
+
208
+ should "return the jobs in random order in order to start working for a new build right away" do
209
+ build1, build2 = Build.create, Build.create
210
+ 20.times { Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build1 }
211
+
212
+ 20.times { Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build2 }
213
+
214
+ build_ids = (0...10).map {
215
+ get '/jobs/next', :version => Testbot.version, :uid => "00:..."
216
+ last_response.body.split(',')[1]
217
+ }
218
+
219
+ assert build_ids.find { |build_id| build_id == build1.id.to_s }
220
+ assert build_ids.find { |build_id| build_id == build2.id.to_s }
221
+ end
222
+
223
+ should "return the jobs randomly when passing build_id" do
224
+ build = Build.create
225
+ 20.times { Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build }
226
+
227
+ 20.times { Job.create :files => 'spec/models/car_spec.rb', :root => 'server:/project', :type => 'spec', :build => build }
228
+
229
+ files = (0...10).map {
230
+ get '/jobs/next', :version => Testbot.version, :uid => "00:...", :build_id => build.id
231
+ last_response.body.split(',').last
232
+ }
233
+
234
+ assert files.find { |file| file.include?('car') }
235
+ assert files.find { |file| file.include?('house') }
236
+ end
237
+
238
+ should "return taken jobs to other runners if the runner hasn't been seen for 10 seconds or more" do
239
+ missing_runner = Runner.create(:last_seen_at => Time.now - 15)
240
+ build = Build.create
241
+ old_taken_job = Job.create :files => 'spec/models/house_spec.rb', :root => 'server:/project', :type => 'spec', :build => build, :taken_by => missing_runner, :taken_at => Time.now - 30, :project => 'things'
242
+
243
+ new_runner = Runner.create(:uid => "00:01")
244
+ get '/jobs/next', :version => Testbot.version, :uid => "00:01"
245
+ assert_equal new_runner, old_taken_job.taken_by
246
+
247
+ assert last_response.ok?
248
+ assert_equal [ old_taken_job.id, build.id.to_s, "things", "server:/project", "spec", "ruby", "spec/models/house_spec.rb" ].join(','), last_response.body
249
+ end
250
+
251
+ end
252
+
253
+ context "/runners/outdated" do
254
+
255
+ should "return a list of outdated runners" do
256
+ get '/jobs/next', :version => "1", :hostname => 'macmini1.local', :uid => "00:01"
257
+ get '/jobs/next', :version => "1", :hostname => 'macmini2.local', :uid => "00:02"
258
+ get '/jobs/next'
259
+ get '/jobs/next', :version => Testbot.version.to_s, :hostname => 'macmini3.local', :uid => "00:03"
260
+ assert_equal 4, Runner.count
261
+ get '/runners/outdated'
262
+ assert last_response.ok?
263
+ assert_equal "127.0.0.1 macmini1.local 00:01\n127.0.0.1 macmini2.local 00:02\n127.0.0.1", last_response.body
264
+ end
265
+
266
+ end
267
+
268
+ context "GET /runners/available_runners" do
269
+
270
+ should "return a list of available runners" do
271
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :idle_instances => 2, :username => 'user1'
272
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4, :username => 'user2'
273
+ get '/runners/available'
274
+ assert last_response.ok?
275
+ assert_equal "127.0.0.1 macmini1.local 00:01 user1 2\n127.0.0.1 macmini2.local 00:02 user2 4", last_response.body
276
+ end
277
+
278
+ should "not return a runner as available when it hasnt pinged the server yet" do
279
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :username => 'user1'
280
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4, :username => 'user2'
281
+ get '/runners/available'
282
+ assert last_response.ok?
283
+ assert_equal "127.0.0.1 macmini2.local 00:02 user2 4", last_response.body
284
+ end
285
+
286
+ should "not return runners as available when not seen the last 10 seconds" do
287
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :idle_instances => 2, :username => "user1"
288
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4
289
+ Runner.find_by_uid("00:02").update(:last_seen_at => Time.now - 10)
290
+ get '/runners/available'
291
+ assert_equal "127.0.0.1 macmini1.local 00:01 user1 2", last_response.body
292
+ end
293
+
294
+ end
295
+
296
+ context "GET /runners/available_instances" do
297
+
298
+ should "return the number of available runner instances" do
299
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :idle_instances => 2
300
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4
301
+ get '/runners/available_instances'
302
+ assert last_response.ok?
303
+ assert_equal "6", last_response.body
304
+ end
305
+
306
+ should "not return instances as available when not seen the last 10 seconds" do
307
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :idle_instances => 2
308
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4
309
+ Runner.find_by_uid("00:02").update(:last_seen_at => Time.now - 10)
310
+ get '/runners/available_instances'
311
+ assert last_response.ok?
312
+ assert_equal "2", last_response.body
313
+ end
314
+
315
+ end
316
+
317
+ context "GET /runners/total_instances" do
318
+
319
+ should "return the number of available runner instances" do
320
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :max_instances => 2, :idle_instances => 1
321
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :max_instances => 4, :idle_instances => 2
322
+ get '/runners/total_instances'
323
+ assert last_response.ok?
324
+ assert_equal "6", last_response.body
325
+ end
326
+
327
+ should "not return instances as available when not seen the last 10 seconds" do
328
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :max_instances => 2, :idle_instances => 1
329
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :max_instances => 4, :idle_instances => 2
330
+ Runner.find_by_uid("00:02").update(:last_seen_at => Time.now - 10)
331
+ get '/runners/total_instances'
332
+ assert last_response.ok?
333
+ assert_equal "2", last_response.body
334
+ end
335
+
336
+ end
337
+
338
+ context "GET /runners/ping" do
339
+
340
+ should "update last_seen_at for the runner" do
341
+ runner = Runner.create(:uid => 'aa:aa:aa:aa:aa:aa')
342
+ get "/runners/ping", :uid => 'aa:aa:aa:aa:aa:aa', :version => Testbot.version
343
+ assert last_response.ok?
344
+ assert (Time.now - 5) < runner.last_seen_at
345
+ assert (Time.now + 5) > runner.last_seen_at
346
+ end
347
+
348
+ should "update data on the runner" do
349
+ build = Build.create
350
+ runner = Runner.create(:uid => 'aa:aa:..')
351
+ get "/runners/ping", :uid => 'aa:aa:..', :max_instances => 4, :idle_instances => 2, :hostname => "hostname1", :version => Testbot.version, :username => 'jocke', :build_id => build.id
352
+ assert last_response.ok?
353
+ assert_equal 'aa:aa:..', runner.uid
354
+ assert_equal 4, runner.max_instances
355
+ assert_equal 2, runner.idle_instances
356
+ assert_equal 'hostname1', runner.hostname
357
+ assert_equal Testbot.version, runner.version
358
+ assert_equal 'jocke', runner.username
359
+ assert_equal build, runner.build
360
+ end
361
+
362
+ should "do nothing if the version does not match" do
363
+ runner = Runner.create(:uid => 'aa:aa:..', :version => Testbot.version)
364
+ get "/runners/ping", :uid => 'aa:aa:..', :version => "OLD"
365
+ assert last_response.ok?
366
+ assert_equal Testbot.version, runner.version
367
+ end
368
+
369
+ should "do nothing if the runners isnt known yet found" do
370
+ get "/runners/ping", :uid => 'aa:aa:aa:aa:aa:aa', :version => Testbot.version
371
+ assert last_response.ok?
372
+ end
373
+
374
+ should "return an order to stop the build if the build id does not exist anymore" do
375
+ runner = Runner.create(:uid => 'aa:aa:..')
376
+ get "/runners/ping", :uid => 'aa:aa:..', :max_instances => 4, :idle_instances => 2, :hostname => "hostname1", :version => Testbot.version, :username => 'jocke', :build_id => 1
377
+ assert_equal last_response.body, "stop_build,1"
378
+ end
379
+
380
+ should "not return an order to stop a build without an id" do
381
+ runner = Runner.create(:uid => 'aa:aa:..')
382
+ get "/runners/ping", :uid => 'aa:aa:..', :max_instances => 4, :idle_instances => 2, :hostname => "hostname1", :version => Testbot.version, :username => 'jocke', :build_id => ''
383
+ assert_equal last_response.body, ''
384
+ get "/runners/ping", :uid => 'aa:aa:..', :max_instances => 4, :idle_instances => 2, :hostname => "hostname1", :version => Testbot.version, :username => 'jocke', :build_id => nil
385
+ assert_equal last_response.body, ''
386
+ end
387
+
388
+ end
389
+
390
+ context "PUT /jobs/:id" do
391
+
392
+ should "receive the results of a job" do
393
+ job = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30
394
+ put "/jobs/#{job.id}", :result => 'test run result', :status => "successful"
395
+ assert last_response.ok?
396
+ assert_equal 'test run result', job.result
397
+ assert_equal 'successful', job.status
398
+ end
399
+
400
+ should "update the related build" do
401
+ build = Build.create
402
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
403
+ job2 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
404
+ put "/jobs/#{job1.id}", :result => 'test run result 1\n', :status => "successful"
405
+ put "/jobs/#{job2.id}", :result => 'test run result 2\n', :status => "successful"
406
+ assert_equal 'test run result 1\ntest run result 2\n', build.results
407
+ assert_equal true, build.success
408
+ end
409
+
410
+ should "make the related build done if there are no more jobs for the build" do
411
+ build = Build.create
412
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
413
+ job2 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
414
+ put "/jobs/#{job1.id}", :result => 'test run result 1\n', :status => "successful"
415
+ put "/jobs/#{job2.id}", :result => 'test run result 2\n', :status => "successful"
416
+ assert_equal true, build.done
417
+ end
418
+
419
+ should "make the build fail if one of the jobs fail" do
420
+ build = Build.create
421
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
422
+ job2 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
423
+ put "/jobs/#{job1.id}", :result => 'test run result 1\n', :status => "failed"
424
+ put "/jobs/#{job2.id}", :result => 'test run result 2\n', :status => "successful"
425
+ assert_equal false, build.success
426
+ end
427
+
428
+ should "be able to update from multiple result postings" do
429
+ build = Build.create
430
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
431
+ job2 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
432
+ # maybe later:
433
+ # put "/jobs/#{job.id}", :result => 'Preparing, db setup, etc.', :status => "preparing"
434
+ put "/jobs/#{job1.id}", :result => 'Running tests..', :status => "running"
435
+ put "/jobs/#{job2.id}", :result => 'Running other tests. done.', :status => "successful"
436
+ put "/jobs/#{job1.id}", :result => 'Running tests....', :status => "running"
437
+ assert_equal false, build.done
438
+ assert_equal false, job1.done
439
+ assert_equal "Running tests....", job1.result
440
+ assert_equal "Running tests..Running other tests. done...", build.results
441
+ end
442
+
443
+ should "not break when updating without new results" do
444
+ build = Build.create
445
+ job1 = Job.create :files => 'spec/models/car_spec.rb', :taken_at => Time.now - 30, :build => build
446
+ put "/jobs/#{job1.id}", :result => 'Running tests..', :status => "running"
447
+ put "/jobs/#{job1.id}", :result => '', :status => "successful"
448
+ assert_equal "Running tests..", build.results
449
+ end
450
+
451
+ end
452
+
453
+ context "GET /version" do
454
+
455
+ should "return its version" do
456
+ get '/version'
457
+ assert last_response.ok?
458
+ assert_equal Testbot.version.to_s, last_response.body
459
+ end
460
+
461
+ end
462
+
463
+ context "GET /runners" do
464
+
465
+ should "return runner information in json format" do
466
+ get '/jobs/next', :version => Testbot.version, :uid => "00:01"
467
+ get "/runners/ping", :uid => '00:01', :max_instances => 4, :idle_instances => 2, :hostname => "hostname1", :version => Testbot.version, :username => 'testbot', :build_id => nil
468
+ get '/runners'
469
+
470
+ assert last_response.ok?
471
+ assert_equal ([ { "version" => Testbot.version.to_s, "build" => nil, "hostname" => 'hostname1', "uid" => "00:01",
472
+ "idle_instances" => 2, "max_instances" => 4, "username" => 'testbot',
473
+ "ip" => "127.0.0.1", "last_seen_at" => Runner.first.last_seen_at.to_s } ]),
474
+ JSON.parse(last_response.body)
475
+ end
476
+
477
+ should "not return instances when not seen the last 10 seconds" do
478
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini1.local', :uid => "00:01", :idle_instances => 2
479
+ get '/jobs/next', :version => Testbot.version, :hostname => 'macmini2.local', :uid => "00:02", :idle_instances => 4
480
+ Runner.find_by_uid("00:02").update(:last_seen_at => Time.now - 10)
481
+ get '/runners'
482
+ assert last_response.ok?
483
+ parsed_body = JSON.parse(last_response.body)
484
+ assert_equal 1, parsed_body.size
485
+ assert_equal '00:01', parsed_body.first["uid"]
486
+ end
487
+
488
+ end
489
+
490
+ context "GET /status" do
491
+
492
+ should "return the contents of the status page" do
493
+ get '/status'
494
+ assert_equal true, last_response.body.include?('Testbot status')
495
+ end
496
+
497
+ end
498
+
499
+ context "GET /status/:dir/:file" do
500
+
501
+ should "return the file" do
502
+ get "/status/javascripts/jquery-1.4.4.min.js"
503
+ assert_equal true, last_response.body.include?('jQuery JavaScript Library v1.4.4')
504
+ end
505
+
506
+ end
507
+
508
+ end
509
+
510
+ end
511
+
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/shared/adapters/adapter.rb'))
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ class AdapterTest < Test::Unit::TestCase
6
+
7
+ should "be able to find adapters" do
8
+ assert_equal RspecAdapter, Adapter.find(:spec)
9
+ assert_equal TestUnitAdapter, Adapter.find(:test)
10
+ end
11
+
12
+ should "find be able to find an adapter by string" do
13
+ assert_equal RspecAdapter, Adapter.find("spec")
14
+ assert_equal TestUnitAdapter, Adapter.find("test")
15
+ end
16
+
17
+ should "be able to return a list of adapters" do
18
+ assert Adapter.all.include?(RspecAdapter)
19
+ assert Adapter.all.include?(TestUnitAdapter)
20
+ end
21
+
22
+ end
@@ -0,0 +1,72 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/shared/adapters/cucumber_adapter.rb'))
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ class CucumberAdapterTest < Test::Unit::TestCase
6
+
7
+ context "sum_results" do
8
+
9
+ should "be able to parse and sum results" do
10
+ results =<<STR
11
+ testbot4:/tmp/testbot
12
+ ............................................................................................................................................................
13
+
14
+ 13 scenarios (\033[32m13 passed\033[0m)
15
+ 153 steps (\033[32m153 passed\033[0m)
16
+ 0m25.537s
17
+
18
+ testbot3:/tmp/testbot
19
+ ................................................................................................................
20
+
21
+ 12 scenarios (\033[32m12 passed\033[0m)
22
+ 109 steps (\033[32m109 passed\033[0m)
23
+ 1m28.472s
24
+ STR
25
+
26
+ assert_equal "25 scenarios (25 passed)\n262 steps (262 passed)", Color.strip(CucumberAdapter.sum_results(results))
27
+ end
28
+
29
+
30
+ should "should handle undefined steps" do
31
+ results =<<STR
32
+ 5 scenarios (1 failed, 1 undefined, 3 passed)
33
+ 42 steps (1 failed, 3 skipped, 1 undefined, 37 passed)
34
+
35
+ 5 scenarios (1 failed, 1 undefined, 3 passed)
36
+ 42 steps (1 failed, 3 skipped, 1 undefined, 37 passed)
37
+
38
+ 6 scenarios (6 passed)
39
+ 80 steps (80 passed)
40
+ STR
41
+
42
+ assert_equal "16 scenarios (2 failed, 2 undefined, 12 passed)\n164 steps (2 failed, 6 skipped, 2 undefined, 154 passed)", Color.strip(CucumberAdapter.sum_results(results))
43
+ end
44
+
45
+ should "handle other combinations" do
46
+ results =<<STR
47
+ 5 scenarios (1 failed, 1 undefined, 3 passed)
48
+ 42 steps (1 failed, 1 undefined, 37 passed)
49
+
50
+ 5 scenarios (1 failed, 1 undefined, 3 passed)
51
+ 42 steps (3 skipped, 1 undefined, 37 passed)
52
+
53
+ 6 scenarios (6 passed)
54
+ 80 steps (80 passed)
55
+ STR
56
+
57
+ assert_equal "16 scenarios (2 failed, 2 undefined, 12 passed)\n164 steps (1 failed, 3 skipped, 2 undefined, 154 passed)", Color.strip(CucumberAdapter.sum_results(results))
58
+ end
59
+
60
+ should "colorize" do
61
+ results =<<STR
62
+ 5 scenarios (1 failed, 1 undefined, 3 passed)
63
+ 42 steps (1 failed, 3 skipped, 1 undefined, 37 passed)
64
+ STR
65
+
66
+ assert_equal "5 scenarios (\e[31m1 failed\e[0m, \e[33m1 undefined\e[0m, \e[32m3 passed\e[0m)\n42 steps (\e[31m1 failed\e[0m, \e[36m3 skipped\e[0m, \e[33m1 undefined\e[0m, \e[32m37 passed\e[0m)", CucumberAdapter.sum_results(results)
67
+ end
68
+
69
+ end
70
+
71
+
72
+ end