spassky 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +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
|