js_spec 0.2.1 → 0.3.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/CHANGES +12 -0
- data/README +2 -1
- data/Rakefile +2 -3
- data/core/JSSpecExtensions.js +18 -16
- data/lib/js_spec/resources/{spec_runner.rb → spec.rb} +4 -8
- data/lib/js_spec/resources.rb +1 -10
- data/lib/js_spec.rb +19 -20
- data/spec/integration/integration_spec.rb +14 -3
- data/spec/integration/integration_spec_helper.rb +1 -2
- data/spec/unit/js_test_core/resources/spec_dir_spec.rb +35 -0
- data/spec/unit/js_test_core/resources/spec_file_spec.rb +33 -0
- data/spec/unit/unit_spec_helper.rb +9 -9
- metadata +7 -46
- data/core/jquery.js +0 -2992
- data/lib/js_spec/client.rb +0 -50
- data/lib/js_spec/guid.rb +0 -153
- data/lib/js_spec/rack/commonlogger.rb +0 -5
- data/lib/js_spec/rack.rb +0 -2
- data/lib/js_spec/rails_server.rb +0 -22
- data/lib/js_spec/resources/dir.rb +0 -60
- data/lib/js_spec/resources/file.rb +0 -32
- data/lib/js_spec/resources/runners/firefox_runner.rb +0 -71
- data/lib/js_spec/resources/runners.rb +0 -15
- data/lib/js_spec/resources/spec_dir_runner.rb +0 -15
- data/lib/js_spec/resources/spec_file_runner.rb +0 -15
- data/lib/js_spec/resources/suite.rb +0 -24
- data/lib/js_spec/resources/suite_finish.rb +0 -20
- data/lib/js_spec/resources/web_root.rb +0 -34
- data/lib/js_spec/server.rb +0 -98
- data/lib/js_spec/thin/backends/js_spec_server.rb +0 -9
- data/lib/js_spec/thin/js_spec_connection.rb +0 -42
- data/lib/js_spec/thin.rb +0 -3
- data/spec/unit/js_spec/client_spec.rb +0 -137
- data/spec/unit/js_spec/rails_server_spec.rb +0 -45
- data/spec/unit/js_spec/resources/dir_spec.rb +0 -84
- data/spec/unit/js_spec/resources/file_spec.rb +0 -87
- data/spec/unit/js_spec/resources/runner_spec.rb +0 -24
- data/spec/unit/js_spec/resources/runners/firefox_runner_spec.rb +0 -152
- data/spec/unit/js_spec/resources/spec_dir_runner_spec.rb +0 -48
- data/spec/unit/js_spec/resources/spec_file_runner_spec.rb +0 -20
- data/spec/unit/js_spec/resources/suite_finish_spec.rb +0 -42
- data/spec/unit/js_spec/resources/suite_spec.rb +0 -44
- data/spec/unit/js_spec/resources/web_root_spec.rb +0 -55
- data/spec/unit/js_spec/server_spec.rb +0 -154
- data/spec/unit/thin/js_spec_connection_spec.rb +0 -64
data/lib/js_spec/client.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
class Client
|
3
|
-
class << self
|
4
|
-
def run(params={})
|
5
|
-
data = []
|
6
|
-
data << "selenium_host=#{CGI.escape(params[:selenium_host] || 'localhost')}"
|
7
|
-
data << "selenium_port=#{CGI.escape((params[:selenium_port] || 4444).to_s)}"
|
8
|
-
data << "spec_url=#{CGI.escape(params[:spec_url])}" if params[:spec_url]
|
9
|
-
response = Net::HTTP.start(DEFAULT_HOST, DEFAULT_PORT) do |http|
|
10
|
-
http.post('/runners/firefox', data.join("&"))
|
11
|
-
end
|
12
|
-
|
13
|
-
body = response.body
|
14
|
-
if body.empty?
|
15
|
-
puts "SUCCESS"
|
16
|
-
return true
|
17
|
-
else
|
18
|
-
puts "FAILURE"
|
19
|
-
puts body
|
20
|
-
return false
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def run_argv(argv)
|
25
|
-
params = {}
|
26
|
-
parser = OptionParser.new do |o|
|
27
|
-
o.banner = "JsSpec Runner"
|
28
|
-
o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
|
29
|
-
|
30
|
-
o.on
|
31
|
-
o.on('-h', '--selenium_host=SELENIUM_HOST', "The host name of the Selenium Server relative to where this file is executed") do |host|
|
32
|
-
params[:selenium_host] = host
|
33
|
-
end
|
34
|
-
|
35
|
-
o.on('-p', '--selenium_port=SELENIUM_PORT', "The port of the Selenium Server relative to where this file is executed") do |port|
|
36
|
-
params[:selenium_port] = port
|
37
|
-
end
|
38
|
-
|
39
|
-
o.on('-u', '--spec_url=SPEC_URL', "The url of the js spec server, relative to the browsers running via the Selenium Server") do |spec_url|
|
40
|
-
params[:spec_url] = spec_url
|
41
|
-
end
|
42
|
-
|
43
|
-
o.on_tail
|
44
|
-
end
|
45
|
-
parser.order!(argv)
|
46
|
-
run params
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/js_spec/guid.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Guid - Ruby library for portable GUID/UUID generation.
|
3
|
-
#
|
4
|
-
# Copyright (c) 2004 David Garamond <davegaramond at icqmail com>
|
5
|
-
#
|
6
|
-
# This library is free software; you can redistribute it and/or modify it
|
7
|
-
# under the same terms as Ruby itself.
|
8
|
-
#
|
9
|
-
|
10
|
-
if RUBY_PLATFORM =~ /[^r]win/i &&
|
11
|
-
module Guid_Win32_
|
12
|
-
require 'Win32API'
|
13
|
-
|
14
|
-
PROV_RSA_FULL = 1
|
15
|
-
CRYPT_VERIFYCONTEXT = 0xF0000000
|
16
|
-
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
|
17
|
-
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
|
18
|
-
|
19
|
-
CryptAcquireContext = Win32API.new("advapi32", "CryptAcquireContext",
|
20
|
-
'PPPII', 'L')
|
21
|
-
CryptGenRandom = Win32API.new("advapi32", "CryptGenRandom",
|
22
|
-
'LIP', 'L')
|
23
|
-
CryptReleaseContext = Win32API.new("advapi32", "CryptReleaseContext",
|
24
|
-
'LI', 'L')
|
25
|
-
GetLastError = Win32API.new("kernel32", "GetLastError", '', 'L')
|
26
|
-
FormatMessageA = Win32API.new("kernel32", "FormatMessageA",
|
27
|
-
'LPLLPLPPPPPPPP', 'L')
|
28
|
-
|
29
|
-
def lastErrorMessage
|
30
|
-
code = GetLastError.call
|
31
|
-
msg = "\0" * 1024
|
32
|
-
len = FormatMessageA.call(FORMAT_MESSAGE_IGNORE_INSERTS +
|
33
|
-
FORMAT_MESSAGE_FROM_SYSTEM, 0,
|
34
|
-
code, 0, msg, 1024, nil, nil,
|
35
|
-
nil, nil, nil, nil, nil, nil)
|
36
|
-
msg[0, len].tr("\r", '').chomp
|
37
|
-
end
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
hProvStr = " " * 4
|
41
|
-
if CryptAcquireContext.call(hProvStr, nil, nil, PROV_RSA_FULL,
|
42
|
-
CRYPT_VERIFYCONTEXT) == 0
|
43
|
-
raise SystemCallError, "CryptAcquireContext failed: #{lastErrorMessage}"
|
44
|
-
end
|
45
|
-
hProv, = hProvStr.unpack('L')
|
46
|
-
@bytes = " " * 16
|
47
|
-
if CryptGenRandom.call(hProv, 16, @bytes) == 0
|
48
|
-
raise SystemCallError, "CryptGenRandom failed: #{lastErrorMessage}"
|
49
|
-
end
|
50
|
-
if CryptReleaseContext.call(hProv, 0) == 0
|
51
|
-
raise SystemCallError, "CryptReleaseContext failed: #{lastErrorMessage}"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
module Guid_Unix_
|
58
|
-
@@random_device = nil
|
59
|
-
|
60
|
-
def initialize
|
61
|
-
if !@@random_device
|
62
|
-
if File.exists? "/dev/urandom"
|
63
|
-
@@random_device = File.open "/dev/urandom", "r"
|
64
|
-
elsif File.exists? "/dev/random"
|
65
|
-
@@random_device = File.open "/dev/random", "r"
|
66
|
-
else
|
67
|
-
raise RuntimeError, "Can't find random device"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
@bytes = @@random_device.read(16)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class Guid
|
76
|
-
if RUBY_PLATFORM =~ /[^r]win/
|
77
|
-
include Guid_Win32_
|
78
|
-
else
|
79
|
-
include Guid_Unix_
|
80
|
-
end
|
81
|
-
|
82
|
-
def hexdigest
|
83
|
-
@bytes.unpack("h*")[0]
|
84
|
-
end
|
85
|
-
|
86
|
-
def to_s
|
87
|
-
@bytes.unpack("h8 h4 h4 h4 h12").join "-"
|
88
|
-
end
|
89
|
-
|
90
|
-
def inspect
|
91
|
-
to_s
|
92
|
-
end
|
93
|
-
|
94
|
-
def raw
|
95
|
-
@bytes
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.from_s(s)
|
99
|
-
raise ArgumentError, "Invalid GUID hexstring" unless
|
100
|
-
s =~ /\A[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}\z/i
|
101
|
-
guid = Guid.allocate
|
102
|
-
guid.instance_eval { @bytes = [s.gsub(/[^0-9a-f]+/i, '')].pack "h*" }
|
103
|
-
guid
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.from_raw(bytes)
|
107
|
-
raise ArgumentError, "Invalid GUID raw bytes, length must be 16 bytes" unless
|
108
|
-
bytes.length == 16
|
109
|
-
guid = Guid.allocate
|
110
|
-
guid.instance_eval { @bytes = bytes }
|
111
|
-
guid
|
112
|
-
end
|
113
|
-
|
114
|
-
def ==(other)
|
115
|
-
@bytes == other.raw
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
if __FILE__ == $0
|
120
|
-
require 'test/unit'
|
121
|
-
|
122
|
-
class GuidTest < Test::Unit::TestCase
|
123
|
-
def test_new
|
124
|
-
g = Guid.new
|
125
|
-
|
126
|
-
# different representations of guid: hexdigest, hex+dashes, raw bytes
|
127
|
-
assert_equal(0, g.to_s =~ /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
|
128
|
-
assert_equal(16, g.raw.length)
|
129
|
-
assert_equal(0, g.hexdigest =~ /\A[0-9a-f]{32}\z/)
|
130
|
-
assert_equal(g.hexdigest, g.to_s.gsub(/-/, ''))
|
131
|
-
|
132
|
-
# must be different each time we produce (this is just a simple test)
|
133
|
-
g2 = Guid.new
|
134
|
-
assert_equal(true, g != g2)
|
135
|
-
assert_equal(true, g.to_s != g2.to_s)
|
136
|
-
assert_equal(true, g.raw != g2.raw)
|
137
|
-
assert_equal(true, g.hexdigest != g2.hexdigest)
|
138
|
-
assert_equal(1000, (1..1000).select { |i| g != Guid.new }.length)
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_from_s
|
142
|
-
g = Guid.new
|
143
|
-
g2 = Guid.from_s(g.to_s)
|
144
|
-
assert_equal(g, g2)
|
145
|
-
end
|
146
|
-
|
147
|
-
def test_from_raw
|
148
|
-
g = Guid.new
|
149
|
-
g2 = Guid.from_raw(g.raw)
|
150
|
-
assert_equal(g, g2)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
data/lib/js_spec/rack.rb
DELETED
data/lib/js_spec/rails_server.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
class RailsServer < Server
|
3
|
-
class << self
|
4
|
-
def run(rails_root, server_options = {})
|
5
|
-
server_options[:Host] ||= DEFAULT_HOST
|
6
|
-
server_options[:Port] ||= DEFAULT_PORT
|
7
|
-
Server.instance = new(rails_root, server_options[:Host], server_options[:Port])
|
8
|
-
Server.instance.run server_options
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(rails_root, host=DEFAULT_HOST, port=DEFAULT_PORT)
|
13
|
-
super(
|
14
|
-
"#{rails_root}/spec/javascripts",
|
15
|
-
"#{rails_root}/public/javascripts",
|
16
|
-
"#{rails_root}/public",
|
17
|
-
host,
|
18
|
-
port
|
19
|
-
)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class Dir < File
|
4
|
-
def locate(name)
|
5
|
-
if file = file(name)
|
6
|
-
file
|
7
|
-
else
|
8
|
-
locate_spec_runner(name)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def get(request, response)
|
13
|
-
SpecDirRunner.new(self).get(request, response)
|
14
|
-
end
|
15
|
-
|
16
|
-
def glob(pattern)
|
17
|
-
expanded_pattern = absolute_path + pattern
|
18
|
-
::Dir.glob(expanded_pattern).map do |absolute_globbed_path|
|
19
|
-
relative_globbed_path = absolute_globbed_path.gsub(absolute_path, relative_path)
|
20
|
-
File.new(absolute_globbed_path, relative_globbed_path)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
def determine_child_paths(name)
|
26
|
-
absolute_child_path = "#{absolute_path}/#{name}"
|
27
|
-
relative_child_path = "#{relative_path}/#{name}"
|
28
|
-
[absolute_child_path, relative_child_path]
|
29
|
-
end
|
30
|
-
|
31
|
-
def locate_spec_runner(name)
|
32
|
-
if subdir = subdir(name)
|
33
|
-
subdir
|
34
|
-
elsif file = file(name + '.js')
|
35
|
-
SpecFileRunner.new(file)
|
36
|
-
else
|
37
|
-
raise "No specs found at #{relative_path}/#{name}."
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def file(name)
|
42
|
-
absolute_file_path, relative_file_path = determine_child_paths(name)
|
43
|
-
if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
|
44
|
-
Resources::File.new(absolute_file_path, relative_file_path)
|
45
|
-
else
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def subdir(name)
|
51
|
-
absolute_dir_path, relative_dir_path = determine_child_paths(name)
|
52
|
-
if ::File.directory?(absolute_dir_path)
|
53
|
-
Resources::Dir.new(absolute_dir_path, relative_dir_path)
|
54
|
-
else
|
55
|
-
nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class File
|
4
|
-
MIME_TYPES = {
|
5
|
-
'.js' => 'text/javascript',
|
6
|
-
'.css' => 'text/css',
|
7
|
-
'.png' => 'image/png',
|
8
|
-
'.jpg' => 'image/jpeg',
|
9
|
-
'.jpeg' => 'image/jpeg',
|
10
|
-
'.gif' => 'image/gif',
|
11
|
-
}
|
12
|
-
|
13
|
-
attr_reader :absolute_path, :relative_path
|
14
|
-
|
15
|
-
def initialize(absolute_path, relative_path)
|
16
|
-
@absolute_path = absolute_path
|
17
|
-
@relative_path = relative_path
|
18
|
-
end
|
19
|
-
|
20
|
-
def get(request, response)
|
21
|
-
extension = ::File.extname(absolute_path)
|
22
|
-
response.headers['Content-Type'] = MIME_TYPES[extension] || 'text/html'
|
23
|
-
response.body = ::File.read(absolute_path)
|
24
|
-
end
|
25
|
-
|
26
|
-
def ==(other)
|
27
|
-
return false unless other.class == self.class
|
28
|
-
absolute_path == other.absolute_path && relative_path == other.relative_path
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class Runners
|
4
|
-
class FirefoxRunner
|
5
|
-
class << self
|
6
|
-
def resume(guid, text)
|
7
|
-
runner = instances.delete(guid)
|
8
|
-
runner.finalize(text)
|
9
|
-
end
|
10
|
-
|
11
|
-
def register_instance(runner)
|
12
|
-
instances[runner.guid] = runner
|
13
|
-
end
|
14
|
-
|
15
|
-
protected
|
16
|
-
def instances
|
17
|
-
@instances ||= {}
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
include FileUtils
|
22
|
-
attr_reader :guid, :profile_dir, :request, :response, :connection, :driver
|
23
|
-
|
24
|
-
def initialize(request, response)
|
25
|
-
profile_base = "#{::Dir.tmpdir}/js_spec/firefox"
|
26
|
-
mkdir_p profile_base
|
27
|
-
@profile_dir = "#{profile_base}/#{Time.now.to_i}"
|
28
|
-
@guid = Guid.new.to_s
|
29
|
-
@request = request
|
30
|
-
@response = response
|
31
|
-
@connection = Server.connection
|
32
|
-
end
|
33
|
-
|
34
|
-
def post(request, response)
|
35
|
-
FirefoxRunner.register_instance self
|
36
|
-
spec_url = (request && request['spec_url']) ? request['spec_url'] : spec_suite_url
|
37
|
-
parsed_spec_url = URI.parse(spec_url)
|
38
|
-
selenium_port = (request['selenium_port'] || 4444).to_i
|
39
|
-
@driver = Selenium::SeleniumDriver.new(
|
40
|
-
request['selenium_host'] || 'localhost',
|
41
|
-
selenium_port,
|
42
|
-
'*firefox',
|
43
|
-
"#{parsed_spec_url.scheme}://#{parsed_spec_url.host}:#{parsed_spec_url.port}"
|
44
|
-
)
|
45
|
-
begin
|
46
|
-
driver.start
|
47
|
-
rescue Errno::ECONNREFUSED => e
|
48
|
-
raise Errno::ECONNREFUSED, "Cannot connect to Selenium Server on port #{selenium_port}. To start the selenium server, run `selenium`."
|
49
|
-
end
|
50
|
-
Thread.start do
|
51
|
-
url = "#{spec_url}?guid=#{guid}"
|
52
|
-
driver.open(url)
|
53
|
-
end
|
54
|
-
response.status = 200
|
55
|
-
end
|
56
|
-
|
57
|
-
def finalize(text)
|
58
|
-
driver.stop
|
59
|
-
response.body = text
|
60
|
-
connection.send_body(response)
|
61
|
-
end
|
62
|
-
|
63
|
-
protected
|
64
|
-
|
65
|
-
def spec_suite_url
|
66
|
-
"#{Server.root_url}/specs"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class Suite
|
4
|
-
class << self
|
5
|
-
def locate(id)
|
6
|
-
new id
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
attr_reader :id
|
11
|
-
def initialize(id)
|
12
|
-
@id = id
|
13
|
-
end
|
14
|
-
|
15
|
-
def locate(name)
|
16
|
-
if name == 'finish'
|
17
|
-
SuiteFinish.new self
|
18
|
-
else
|
19
|
-
raise ArgumentError, "Invalid path: #{name}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class SuiteFinish
|
4
|
-
attr_reader :suite
|
5
|
-
def initialize(suite)
|
6
|
-
@suite = suite
|
7
|
-
end
|
8
|
-
|
9
|
-
def post(request, response)
|
10
|
-
guid = request['guid']
|
11
|
-
if guid
|
12
|
-
Runners::FirefoxRunner.resume(guid, request['text'])
|
13
|
-
else
|
14
|
-
STDOUT.puts request['text']
|
15
|
-
end
|
16
|
-
""
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
module Resources
|
3
|
-
class WebRoot
|
4
|
-
attr_reader :public_path
|
5
|
-
def initialize(public_path)
|
6
|
-
@public_path = ::File.expand_path(public_path)
|
7
|
-
end
|
8
|
-
|
9
|
-
def locate(name)
|
10
|
-
case name
|
11
|
-
when 'specs'
|
12
|
-
Resources::Dir.new(JsSpec::Server.spec_root_path, "/specs")
|
13
|
-
when 'core'
|
14
|
-
Resources::Dir.new(JsSpec::Server.core_path, "/core")
|
15
|
-
when 'implementations'
|
16
|
-
Resources::Dir.new(JsSpec::Server.implementation_root_path, "/implementations")
|
17
|
-
when 'suites'
|
18
|
-
Resources::Suite
|
19
|
-
when 'runners'
|
20
|
-
Resources::Runners.new
|
21
|
-
else
|
22
|
-
potential_file_in_public_path = "#{public_path}/#{name}"
|
23
|
-
if ::File.directory?(potential_file_in_public_path)
|
24
|
-
Resources::Dir.new(potential_file_in_public_path, "/#{name}")
|
25
|
-
elsif ::File.exists?(potential_file_in_public_path)
|
26
|
-
Resources::File.new(potential_file_in_public_path, "/#{name}")
|
27
|
-
else
|
28
|
-
raise "Invalid path: #{name}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/js_spec/server.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
module JsSpec
|
2
|
-
class Server
|
3
|
-
class << self
|
4
|
-
attr_accessor :instance
|
5
|
-
|
6
|
-
def run(spec_root_path, implementation_root_path, public_path, server_options = {})
|
7
|
-
server_options[:Host] ||= DEFAULT_HOST
|
8
|
-
server_options[:Port] ||= DEFAULT_PORT
|
9
|
-
@instance = new(spec_root_path, implementation_root_path, public_path, server_options[:Host], server_options[:Port])
|
10
|
-
instance.run server_options
|
11
|
-
end
|
12
|
-
|
13
|
-
def spec_root_path; instance.spec_root_path; end
|
14
|
-
def implementation_root_path; instance.implementation_root_path; end
|
15
|
-
def public_path; instance.public_path; end
|
16
|
-
def core_path; instance.core_path; end
|
17
|
-
def connection; instance.connection; end
|
18
|
-
def request; instance.request; end
|
19
|
-
def response; instance.response; end
|
20
|
-
def root_url; instance.root_url; end
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_reader :host, :port, :spec_root_path, :implementation_root_path, :core_path, :public_path
|
24
|
-
|
25
|
-
def initialize(spec_root_path, implementation_root_path, public_path, host=DEFAULT_HOST, port=DEFAULT_PORT)
|
26
|
-
dir = ::File.dirname(__FILE__)
|
27
|
-
@core_path = ::File.expand_path("#{dir}/../../core")
|
28
|
-
@spec_root_path = ::File.expand_path(spec_root_path)
|
29
|
-
@implementation_root_path = ::File.expand_path(implementation_root_path)
|
30
|
-
@public_path = ::File.expand_path(public_path)
|
31
|
-
@host = host
|
32
|
-
@port = port
|
33
|
-
end
|
34
|
-
|
35
|
-
def run(options)
|
36
|
-
server = ::Thin::Server.new(options[:Host], options[:Port], self)
|
37
|
-
server.backend = ::Thin::Backends::JsSpecServer.new(options[:Host], options[:Port])
|
38
|
-
server.backend.server = server
|
39
|
-
server.start!
|
40
|
-
end
|
41
|
-
|
42
|
-
def call(env)
|
43
|
-
self.connection = env['js_spec.connection']
|
44
|
-
self.request = Rack::Request.new(env)
|
45
|
-
self.response = Rack::Response.new
|
46
|
-
method = request.request_method.downcase.to_sym
|
47
|
-
get_resource(request).send(method, request, response)
|
48
|
-
response.finish
|
49
|
-
ensure
|
50
|
-
self.connection = nil
|
51
|
-
self.request = nil
|
52
|
-
self.response = nil
|
53
|
-
end
|
54
|
-
|
55
|
-
def connection
|
56
|
-
Thread.current[:connection]
|
57
|
-
end
|
58
|
-
|
59
|
-
def request
|
60
|
-
Thread.current[:request]
|
61
|
-
end
|
62
|
-
|
63
|
-
def response
|
64
|
-
Thread.current[:response]
|
65
|
-
end
|
66
|
-
|
67
|
-
def root_url
|
68
|
-
"http://#{host}:#{port}"
|
69
|
-
end
|
70
|
-
|
71
|
-
protected
|
72
|
-
def connection=(connection)
|
73
|
-
Thread.current[:connection] = connection
|
74
|
-
end
|
75
|
-
|
76
|
-
def request=(request)
|
77
|
-
Thread.current[:request] = request
|
78
|
-
end
|
79
|
-
|
80
|
-
def response=(response)
|
81
|
-
Thread.current[:response] = response
|
82
|
-
end
|
83
|
-
|
84
|
-
def path_parts(req)
|
85
|
-
request.path_info.split('/').reject { |part| part == "" }
|
86
|
-
end
|
87
|
-
|
88
|
-
def get_resource(request)
|
89
|
-
path_parts(request).inject(Resources::WebRoot.new(public_path)) do |resource, child_resource_name|
|
90
|
-
resource.locate(child_resource_name)
|
91
|
-
end
|
92
|
-
rescue Exception => e
|
93
|
-
detailed_exception = Exception.new("Error handling path #{request.path_info}\n#{e.message}")
|
94
|
-
detailed_exception.set_backtrace(e.backtrace)
|
95
|
-
raise detailed_exception
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Thin
|
2
|
-
class JsSpecConnection < Connection
|
3
|
-
def process
|
4
|
-
# Add client info to the request env
|
5
|
-
@request.remote_address = remote_address
|
6
|
-
|
7
|
-
env = @request.env
|
8
|
-
env['js_spec.connection'] = self
|
9
|
-
@response.status, @response.headers, @response.body = @app.call(env)
|
10
|
-
send_data @response.head
|
11
|
-
unless @response.body.empty?
|
12
|
-
send_body @response.body
|
13
|
-
end
|
14
|
-
rescue Exception => e
|
15
|
-
handle_error e
|
16
|
-
end
|
17
|
-
|
18
|
-
def send_body(rack_response)
|
19
|
-
rack_response.each do |chunk|
|
20
|
-
send_data chunk
|
21
|
-
end
|
22
|
-
# If no more request on that same connection, we close it.
|
23
|
-
close_connection_after_writing unless persistent?
|
24
|
-
rescue Exception => e
|
25
|
-
handle_error e
|
26
|
-
ensure
|
27
|
-
@request.close rescue nil
|
28
|
-
@response.close rescue nil
|
29
|
-
|
30
|
-
# Prepare the connection for another request if the client
|
31
|
-
# supports HTTP pipelining (persistent connection).
|
32
|
-
post_init if persistent?
|
33
|
-
end
|
34
|
-
|
35
|
-
def handle_error(error)
|
36
|
-
log "!! Unexpected error while processing request: #{error.message}"
|
37
|
-
log error.backtrace
|
38
|
-
log_error
|
39
|
-
close_connection rescue nil
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/js_spec/thin.rb
DELETED