spassky 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +84 -0
- data/LICENSE +13 -0
- data/README.md +47 -0
- data/Rakefile +5 -0
- data/bin/spassky +8 -0
- data/bin/spassky-server +9 -0
- data/config.ru +6 -0
- data/features/connection.feature +9 -0
- data/features/device_timeout.feature +31 -0
- data/features/run_html_tests.feature +65 -0
- data/features/run_qunit_tests.feature +45 -0
- data/features/server.feature +11 -0
- data/features/step_definitions/steps.rb +66 -0
- data/features/support/env.rb +31 -0
- data/features/support/fixtures/qunit.js +1512 -0
- data/lib/spassky/client/cli.rb +12 -0
- data/lib/spassky/client/directory_reader.rb +14 -0
- data/lib/spassky/client/pusher.rb +36 -0
- data/lib/spassky/client/test_runner.rb +44 -0
- data/lib/spassky/client/writer.rb +31 -0
- data/lib/spassky/client.rb +1 -0
- data/lib/spassky/server/app.rb +76 -0
- data/lib/spassky/server/assert.js +5 -0
- data/lib/spassky/server/device_list.rb +18 -0
- data/lib/spassky/server/html_test.rb +27 -0
- data/lib/spassky/server/random_string_generator.rb +7 -0
- data/lib/spassky/server/test_run.rb +64 -0
- data/lib/spassky/server.rb +1 -0
- data/lib/spassky/test_result.rb +110 -0
- data/lib/spassky/version.rb +3 -0
- data/lib/spassky.rb +9 -0
- data/spassky.gemspec +31 -0
- data/spec/spassky/client/cli_spec.rb +48 -0
- data/spec/spassky/client/directory_reader_spec.rb +35 -0
- data/spec/spassky/client/pusher_spec.rb +72 -0
- data/spec/spassky/client/test_runner_spec.rb +130 -0
- data/spec/spassky/client/writer_spec.rb +31 -0
- data/spec/spassky/server/app_spec.rb +177 -0
- data/spec/spassky/server/device_list_spec.rb +32 -0
- data/spec/spassky/server/random_string_generator_spec.rb +13 -0
- data/spec/spassky/server/test_run_spec.rb +98 -0
- data/spec/spassky/test_result_spec.rb +116 -0
- data/spec/spec_helper.rb +3 -0
- metadata +215 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spassky/client/test_runner'
|
2
|
+
require 'spassky/client/pusher'
|
3
|
+
require 'spassky/client/directory_reader'
|
4
|
+
|
5
|
+
module Spassky::Client
|
6
|
+
class Cli
|
7
|
+
def self.run(argv)
|
8
|
+
writer = argv.include?('--colour') ? ColouredWriter : DefaultWriter
|
9
|
+
TestRunner.new(Pusher.new(argv[0]), writer.new(STDOUT), DirectoryReader.new).run_tests(argv[1])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spassky::Client
|
2
|
+
class DirectoryReader
|
3
|
+
def read_files(pattern)
|
4
|
+
if File.file? pattern
|
5
|
+
{ pattern => File.read(pattern) }
|
6
|
+
elsif File.directory? pattern
|
7
|
+
Dir.glob(pattern + "/*").inject({}) do |hash, path|
|
8
|
+
hash[File.basename(path)] = File.read(path)
|
9
|
+
hash
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'spassky/test_result'
|
3
|
+
|
4
|
+
module Spassky::Client
|
5
|
+
class Pusher
|
6
|
+
def initialize(server_url, sleeper=Kernel)
|
7
|
+
@server_url = server_url
|
8
|
+
@sleeper = sleeper
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_runs_url
|
12
|
+
test_runs_url = @server_url.gsub(/\/$/, "") + "/test_runs"
|
13
|
+
end
|
14
|
+
|
15
|
+
def push(options)
|
16
|
+
location = post_test(options)
|
17
|
+
result = nil
|
18
|
+
begin
|
19
|
+
result = Spassky::TestResult.from_json(RestClient.get(location))
|
20
|
+
yield result
|
21
|
+
@sleeper.sleep 0.4 if result.status == 'in progress'
|
22
|
+
end while result.status == 'in progress'
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def post_test(options)
|
28
|
+
location = nil
|
29
|
+
RestClient.post(test_runs_url, options) do |response, request, result|
|
30
|
+
location = response.headers[:location]
|
31
|
+
end
|
32
|
+
raise "Expected #{test_runs_url} to respond with 302" unless location
|
33
|
+
location
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spassky/client/writer'
|
2
|
+
|
3
|
+
module Spassky::Client
|
4
|
+
class TestRunner
|
5
|
+
def initialize(pusher, writer, directory_reader)
|
6
|
+
@pusher = pusher
|
7
|
+
@writer = writer
|
8
|
+
@directory_reader = directory_reader
|
9
|
+
end
|
10
|
+
|
11
|
+
def run_tests(pattern)
|
12
|
+
previous_test_result = nil
|
13
|
+
test_name = File.basename(pattern)
|
14
|
+
@pusher.push(:name => test_name, :contents => @directory_reader.read_files(pattern).to_json) do |result|
|
15
|
+
handle_test_result(previous_test_result, result)
|
16
|
+
previous_test_result = result
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle_test_result(previous_test_result, test_result)
|
21
|
+
write_in_progress_status previous_test_result, test_result
|
22
|
+
unless test_result.status == "in progress"
|
23
|
+
write(test_result.status, test_result.summary)
|
24
|
+
end
|
25
|
+
write_exit_code(test_result)
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_in_progress_status previous_test_result, test_result
|
29
|
+
test_result.completed_since(previous_test_result).each do |device_test_status|
|
30
|
+
write(device_test_status.status, "#{device_test_status.status.upcase} #{device_test_status.test_name} on #{device_test_status.user_agent}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def write status, message
|
35
|
+
method = status == 'pass' ? :write_passing : :write_failing
|
36
|
+
@writer.send(method, message)
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_exit_code(result)
|
40
|
+
Kernel.exit(1) if result.status == 'fail'
|
41
|
+
Kernel.exit(2) if result.status == 'timed out'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rainbow'
|
2
|
+
|
3
|
+
module Spassky::Client
|
4
|
+
class DefaultWriter
|
5
|
+
def initialize(output)
|
6
|
+
@output = output
|
7
|
+
end
|
8
|
+
|
9
|
+
def write_passing(text)
|
10
|
+
@output.puts text
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_failing(text)
|
14
|
+
@output.puts text
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ColouredWriter
|
19
|
+
def initialize(output)
|
20
|
+
@output = output
|
21
|
+
end
|
22
|
+
|
23
|
+
def write_passing(text)
|
24
|
+
@output.puts text.color(:green)
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_failing(text)
|
28
|
+
@output.puts text.color(:red)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'spassky/client/cli'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'spassky/server/random_string_generator'
|
3
|
+
require 'spassky/server/test_run'
|
4
|
+
require 'spassky/server/device_list'
|
5
|
+
require 'spassky/server/html_test'
|
6
|
+
|
7
|
+
module Spassky::Server
|
8
|
+
class App < Sinatra::Base
|
9
|
+
def initialize(device_list=DeviceList.new)
|
10
|
+
@device_list = device_list
|
11
|
+
super()
|
12
|
+
end
|
13
|
+
|
14
|
+
get "/devices/clear" do
|
15
|
+
@device_list.clear
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/device/connect' do
|
19
|
+
redirect idle_url
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/device/idle/:random' do
|
23
|
+
test_run = TestRun.find_next_to_run_for_user_agent(request.user_agent)
|
24
|
+
@device_list.update_last_connected(request.user_agent)
|
25
|
+
if test_run
|
26
|
+
redirect_to_run_tests(test_run)
|
27
|
+
else
|
28
|
+
idle_page
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
post '/test_runs' do
|
33
|
+
run = TestRun.create({
|
34
|
+
:name => params[:name],
|
35
|
+
:contents => JSON.parse(params[:contents]),
|
36
|
+
:devices => @device_list.recently_connected_devices
|
37
|
+
})
|
38
|
+
redirect "/test_runs/#{run.id}"
|
39
|
+
end
|
40
|
+
|
41
|
+
get '/test_runs/:id' do
|
42
|
+
run = TestRun.find(params[:id])
|
43
|
+
run.update_connected_devices(@device_list.recently_connected_devices)
|
44
|
+
run.result.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/test_runs/:id/run/:random/assert' do
|
48
|
+
TestRun.find(params[:id]).save_results_for_user_agent(
|
49
|
+
:user_agent => request.user_agent,
|
50
|
+
:status => params[:status]
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
get '/test_runs/:id/run/:random/:file_name' do
|
55
|
+
test_run = TestRun.find(params[:id])
|
56
|
+
test_name = params[:file_name]
|
57
|
+
HtmlTest.new(test_run.contents, idle_url, 1).get_file(test_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def redirect_to_run_tests(test_run)
|
63
|
+
redirect "/test_runs/#{test_run.id}/run/#{RandomStringGenerator.random_string}/#{test_run.name}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def idle_url
|
67
|
+
"/device/idle/#{RandomStringGenerator.random_string}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def idle_page
|
71
|
+
"<html><head><meta http-equiv=\"refresh\" content=\"1; url='#{idle_url}'\"></head>" +
|
72
|
+
"<body>Idle #{RandomStringGenerator.random_string}</body>" +
|
73
|
+
"</html>"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Spassky::Server
|
2
|
+
class DeviceList
|
3
|
+
def update_last_connected user_agent
|
4
|
+
@devices_and_time_last_connected ||= {}
|
5
|
+
@devices_and_time_last_connected[user_agent] = Time.now
|
6
|
+
end
|
7
|
+
|
8
|
+
def recently_connected_devices
|
9
|
+
@devices_and_time_last_connected.keys.select do |user_agent|
|
10
|
+
Time.now.to_f - @devices_and_time_last_connected[user_agent].to_f < 3
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
15
|
+
@devices_and_time_last_connected = {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Spassky::Server
|
2
|
+
class HtmlTest
|
3
|
+
def initialize(contents, url, seconds)
|
4
|
+
@contents = contents
|
5
|
+
@meta_refresh_tag = "<meta http-equiv=\"refresh\" content=\"#{seconds}; url='#{url}'\">"
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_file(name)
|
9
|
+
file_contents = @contents[name]
|
10
|
+
unless file_contents
|
11
|
+
html_file = @contents.keys.find {|key| key.end_with?(".html")}
|
12
|
+
file_contents = @contents[html_file]
|
13
|
+
end
|
14
|
+
file_contents.gsub('</head>', assert_js_script_tag + @meta_refresh_tag + '</head>')
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def assert_js_script_tag
|
20
|
+
"<script type=\"text/javascript\">#{assert_js_script}</script>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_js_script
|
24
|
+
File.read(File.join(File.dirname(__FILE__), 'assert.js'))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spassky/test_result'
|
2
|
+
|
3
|
+
module Spassky::Server
|
4
|
+
class TestRun
|
5
|
+
attr_accessor :name, :contents, :id
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@name = options[:name]
|
9
|
+
@contents = options[:contents]
|
10
|
+
@status_by_user_agent = {}
|
11
|
+
(options[:devices] || []).each do |device|
|
12
|
+
@status_by_user_agent[device] = "in progress"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_by_user_agent?(user_agent)
|
17
|
+
@status_by_user_agent[user_agent] != "in progress"
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_results_for_user_agent(options)
|
21
|
+
unless ['pass', 'fail'].include? options[:status]
|
22
|
+
raise "#{options[:status]} is not a valid status"
|
23
|
+
end
|
24
|
+
@status_by_user_agent[options[:user_agent]] = options[:status]
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_connected_devices(user_agents)
|
28
|
+
@status_by_user_agent.each do |user_agent, status|
|
29
|
+
if !user_agents.include?(user_agent) && status == "in progress"
|
30
|
+
@status_by_user_agent[user_agent] = "timed out"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def result
|
36
|
+
Spassky::TestResult.new(@status_by_user_agent.map { |user_agent, status|
|
37
|
+
Spassky::DeviceTestStatus.new(user_agent, status, name)
|
38
|
+
})
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.create(options)
|
42
|
+
new_test_run = TestRun.new(options)
|
43
|
+
new_test_run.id = test_runs.size
|
44
|
+
test_runs << new_test_run
|
45
|
+
new_test_run
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find(id)
|
49
|
+
test_runs.find { |test_run| test_run.id.to_s == id.to_s }
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.find_next_to_run_for_user_agent(user_agent)
|
53
|
+
test_runs.find { |test_run| test_run.run_by_user_agent?(user_agent) == false }
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.delete_all
|
57
|
+
@test_runs = []
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.test_runs
|
61
|
+
@test_runs ||= []
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'spassky/server/app'
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Spassky
|
4
|
+
class TestResult
|
5
|
+
attr_reader :device_statuses
|
6
|
+
def initialize device_statuses
|
7
|
+
@device_statuses = device_statuses
|
8
|
+
end
|
9
|
+
|
10
|
+
def status
|
11
|
+
statuses = @device_statuses.map { |s| s.status }.uniq
|
12
|
+
return "in progress" if statuses.include?("in progress") || statuses.size == 0
|
13
|
+
return "fail" if statuses.include?("fail")
|
14
|
+
return "timed out" if statuses.include?("timed out")
|
15
|
+
"pass"
|
16
|
+
end
|
17
|
+
|
18
|
+
def count_fails
|
19
|
+
@device_statuses.count { |s| s.status == "fail" }
|
20
|
+
end
|
21
|
+
|
22
|
+
def count_timeouts
|
23
|
+
@device_statuses.count { |s| s.status == "timed out" }
|
24
|
+
end
|
25
|
+
|
26
|
+
def completed_since(older_test_result)
|
27
|
+
if older_test_result.nil?
|
28
|
+
device_statuses.select { |s| s.completed? }
|
29
|
+
else
|
30
|
+
find_newly_completed_device_results(older_test_result)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def summary
|
35
|
+
result = "?"
|
36
|
+
count = @device_statuses.size
|
37
|
+
if count_timeouts > 0
|
38
|
+
result = "1 test timed out on #{count} device"
|
39
|
+
else
|
40
|
+
status = "passed"
|
41
|
+
fail_count = count_fails
|
42
|
+
if fail_count > 0
|
43
|
+
status = "failed"
|
44
|
+
count = fail_count
|
45
|
+
end
|
46
|
+
result = "1 test #{status} on #{count} device"
|
47
|
+
end
|
48
|
+
result << "s" if @device_statuses.size > 1
|
49
|
+
return result
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json
|
53
|
+
{
|
54
|
+
:status => "pass",
|
55
|
+
:device_statuses => @device_statuses.map do |status|
|
56
|
+
{
|
57
|
+
:user_agent => status.user_agent,
|
58
|
+
:status => status.status,
|
59
|
+
:test_name => status.test_name
|
60
|
+
}
|
61
|
+
end
|
62
|
+
}.to_json
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.from_json json
|
66
|
+
parsed = JSON.parse(json)
|
67
|
+
test_result = TestResult.new(
|
68
|
+
parsed['device_statuses'].map do |t|
|
69
|
+
DeviceTestStatus.new(t["user_agent"], t["status"], t["test_name"])
|
70
|
+
end
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def find_newly_completed_device_results(older_test_result)
|
77
|
+
completed = []
|
78
|
+
before_and_after(older_test_result) do |before, after|
|
79
|
+
if before.in_progress? && after.completed?
|
80
|
+
completed << after
|
81
|
+
end
|
82
|
+
end
|
83
|
+
completed
|
84
|
+
end
|
85
|
+
|
86
|
+
def before_and_after(older_test_result)
|
87
|
+
device_statuses.each_with_index do |s, i|
|
88
|
+
yield older_test_result.device_statuses[i], s
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class DeviceTestStatus
|
94
|
+
attr_reader :user_agent, :status, :test_name
|
95
|
+
|
96
|
+
def initialize(user_agent, status, test_name)
|
97
|
+
@user_agent = user_agent
|
98
|
+
@status = status
|
99
|
+
@test_name = test_name
|
100
|
+
end
|
101
|
+
|
102
|
+
def in_progress?
|
103
|
+
@status == "in progress"
|
104
|
+
end
|
105
|
+
|
106
|
+
def completed?
|
107
|
+
@status != "in progress"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/spassky.rb
ADDED
data/spassky.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "spassky/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "spassky"
|
7
|
+
s.version = Spassky::VERSION
|
8
|
+
s.authors = ["Joshua Chisholm", "Andrew Vos", "Adrian Lewis"]
|
9
|
+
s.email = ["andrew.vos@gmail.com"]
|
10
|
+
s.homepage = "http://github.com/BBC/spassky"
|
11
|
+
s.summary = %q{}
|
12
|
+
s.description = %q{}
|
13
|
+
|
14
|
+
s.rubyforge_project = "spassky"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'rest-client'
|
22
|
+
s.add_dependency 'json'
|
23
|
+
s.add_dependency 'sinatra'
|
24
|
+
s.add_dependency 'rainbow'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'rspec'
|
28
|
+
s.add_development_dependency 'cucumber'
|
29
|
+
s.add_development_dependency 'capybara'
|
30
|
+
s.add_development_dependency 'aruba'
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spassky/client/cli'
|
3
|
+
|
4
|
+
module Spassky::Client
|
5
|
+
describe Cli do
|
6
|
+
let :pusher do
|
7
|
+
mock(:pusher)
|
8
|
+
end
|
9
|
+
|
10
|
+
let :runner do
|
11
|
+
mock(:runner, :run_tests => true)
|
12
|
+
end
|
13
|
+
|
14
|
+
before do
|
15
|
+
Pusher.stub!(:new).and_return(pusher)
|
16
|
+
TestRunner.stub!(:new).and_return(runner)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "creates a pusher with the server url as the first argument" do
|
20
|
+
Pusher.should_receive(:new).with("server_name").and_return(pusher)
|
21
|
+
TestRunner.should_receive(:new).with(pusher, anything(), anything()).and_return(runner)
|
22
|
+
Cli::run(["server_name", "test_name"])
|
23
|
+
end
|
24
|
+
|
25
|
+
it "runs a single test with the name as the second argument" do
|
26
|
+
runner.should_receive(:run_tests).with("test_name")
|
27
|
+
Cli::run(["server_name", "test_name"])
|
28
|
+
end
|
29
|
+
|
30
|
+
context "without colour output option" do
|
31
|
+
it "creates a test runner with a default writer" do
|
32
|
+
default_writer = mock :default_writer
|
33
|
+
DefaultWriter.should_receive(:new).with(STDOUT).and_return(default_writer)
|
34
|
+
TestRunner.should_receive(:new).with(anything(), default_writer, anything())
|
35
|
+
Cli::run(["server_name", "test_name"])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with colour output option" do
|
40
|
+
it "creates a test runner with a colour writer" do
|
41
|
+
coloured_writer = mock :coloured_writer
|
42
|
+
ColouredWriter.should_receive(:new).with(STDOUT).and_return(coloured_writer)
|
43
|
+
TestRunner.should_receive(:new).with(anything(), coloured_writer, anything())
|
44
|
+
Cli::run(["server_name", "test_name", "--colour"])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spassky/client/directory_reader'
|
2
|
+
|
3
|
+
module Spassky::Client
|
4
|
+
describe DirectoryReader do
|
5
|
+
context "when given a file name" do
|
6
|
+
it "returns a hash with one file" do
|
7
|
+
File.should_receive(:file?).and_return(true)
|
8
|
+
File.should_receive(:read).with("foo").and_return("content")
|
9
|
+
DirectoryReader.new.read_files("foo").should == {
|
10
|
+
"foo" => "content"
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
context "when given a directory name" do
|
15
|
+
it "globs for files in the specified directory" do
|
16
|
+
File.stub!(:file?).and_return(false)
|
17
|
+
File.stub!(:directory?).and_return(true)
|
18
|
+
Dir.should_receive(:glob).with("directory/*").and_return([])
|
19
|
+
DirectoryReader.new.read_files("directory")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns a hash with all files in that directory" do
|
23
|
+
File.stub!(:file?).and_return(false)
|
24
|
+
File.stub!(:directory?).and_return(true)
|
25
|
+
Dir.stub!(:glob).and_return ["directory/file1", "directory/file2"]
|
26
|
+
File.stub!(:read).with("directory/file1").and_return("file 1 contents")
|
27
|
+
File.stub!(:read).with("directory/file2").and_return("file 2 contents")
|
28
|
+
DirectoryReader.new.read_files("directory").should == {
|
29
|
+
"file1" => "file 1 contents",
|
30
|
+
"file2" => "file 2 contents"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spassky/client/pusher'
|
3
|
+
|
4
|
+
module Spassky::Client
|
5
|
+
describe Pusher do
|
6
|
+
before do
|
7
|
+
@response = mock("response", :code => 302, :headers => { :location => "http://poll/me" })
|
8
|
+
@server_url = "http://foo/"
|
9
|
+
@sleeper = mock("sleeper")
|
10
|
+
@sleeper.stub!(:sleep)
|
11
|
+
@pusher = Pusher.new(@server_url, @sleeper)
|
12
|
+
RestClient.stub!(:post).with("http://foo/test_runs", "test contents"
|
13
|
+
).and_yield(@response, nil, nil)
|
14
|
+
RestClient.stub!(:get).and_return(passed_status)
|
15
|
+
end
|
16
|
+
|
17
|
+
def in_progress_status
|
18
|
+
Spassky::TestResult.new([Spassky::DeviceTestStatus.new('agent', 'in progress', 'test')]).to_json
|
19
|
+
end
|
20
|
+
|
21
|
+
def passed_status
|
22
|
+
Spassky::TestResult.new([Spassky::DeviceTestStatus.new('agent', 'pass', 'test')]).to_json
|
23
|
+
end
|
24
|
+
|
25
|
+
def failed_status
|
26
|
+
Spassky::TestResult.new([Spassky::DeviceTestStatus.new('agent', 'fail', 'test')]).to_json
|
27
|
+
end
|
28
|
+
|
29
|
+
it "pushes a test to the server" do
|
30
|
+
RestClient.should_receive(:post).with("http://foo/test_runs", {:contents => 'test contents'}
|
31
|
+
).and_yield(@response, nil, nil)
|
32
|
+
@pusher.push({:contents => "test contents"}) do |result|
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "fails nicely when the url does not redirect" do
|
37
|
+
@response = mock("response", :code => 200, :headers => { })
|
38
|
+
RestClient.stub!(:post).with("http://foo/test_runs", "test contents"
|
39
|
+
).and_yield(@response, nil, nil)
|
40
|
+
lambda {
|
41
|
+
@pusher.push("test contents") do |result|
|
42
|
+
end
|
43
|
+
}.should raise_error("Expected http://foo/test_runs to respond with 302")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "polls the URL returned until the test passes" do
|
47
|
+
RestClient.should_receive(:get).with("http://poll/me").and_return(in_progress_status, in_progress_status, in_progress_status, passed_status)
|
48
|
+
@pusher.push("test contents") do |result|
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "polls the URL returned until the test fails" do
|
53
|
+
RestClient.should_receive(:get).and_return(in_progress_status, in_progress_status, failed_status)
|
54
|
+
@pusher.push("test contents") {}
|
55
|
+
end
|
56
|
+
|
57
|
+
it "yields the outcome of the test to the block" do
|
58
|
+
RestClient.stub!(:get).and_return(in_progress_status, in_progress_status, passed_status)
|
59
|
+
yielded_results = []
|
60
|
+
@pusher.push("test contents") do |result|
|
61
|
+
yielded_results << result.to_json
|
62
|
+
end
|
63
|
+
yielded_results.should == [in_progress_status, in_progress_status, passed_status]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "sleeps while looping during get requests" do
|
67
|
+
RestClient.stub!(:get).and_return(in_progress_status, in_progress_status, in_progress_status, passed_status)
|
68
|
+
@sleeper.should_receive(:sleep).with(0.4).exactly(3).times
|
69
|
+
@pusher.push("test contents") { |result| }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|