js_test_core 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGES +9 -0
  2. data/README +12 -0
  3. data/Rakefile +72 -0
  4. data/lib/js_test_core.rb +30 -0
  5. data/lib/js_test_core/client.rb +50 -0
  6. data/lib/js_test_core/rack.rb +2 -0
  7. data/lib/js_test_core/rack/commonlogger.rb +5 -0
  8. data/lib/js_test_core/rails_server.rb +22 -0
  9. data/lib/js_test_core/resources.rb +10 -0
  10. data/lib/js_test_core/resources/dir.rb +52 -0
  11. data/lib/js_test_core/resources/file.rb +32 -0
  12. data/lib/js_test_core/resources/runners.rb +15 -0
  13. data/lib/js_test_core/resources/runners/firefox_runner.rb +73 -0
  14. data/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
  15. data/lib/js_test_core/resources/specs/spec_file.rb +17 -0
  16. data/lib/js_test_core/resources/suite.rb +24 -0
  17. data/lib/js_test_core/resources/suite_finish.rb +19 -0
  18. data/lib/js_test_core/resources/web_root.rb +54 -0
  19. data/lib/js_test_core/selenium.rb +2 -0
  20. data/lib/js_test_core/selenium/selenium_driver.rb +5 -0
  21. data/lib/js_test_core/server.rb +111 -0
  22. data/lib/js_test_core/thin.rb +3 -0
  23. data/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
  24. data/lib/js_test_core/thin/js_test_core_connection.rb +42 -0
  25. data/spec/spec_suite.rb +2 -0
  26. data/spec/unit/js_spec/client_spec.rb +137 -0
  27. data/spec/unit/js_spec/rails_server_spec.rb +45 -0
  28. data/spec/unit/js_spec/resources/dir_spec.rb +42 -0
  29. data/spec/unit/js_spec/resources/file_spec.rb +88 -0
  30. data/spec/unit/js_spec/resources/runner_spec.rb +24 -0
  31. data/spec/unit/js_spec/resources/runners/firefox_runner_spec.rb +161 -0
  32. data/spec/unit/js_spec/resources/specs/spec_dir_spec.rb +79 -0
  33. data/spec/unit/js_spec/resources/specs/spec_file_spec.rb +42 -0
  34. data/spec/unit/js_spec/resources/suite_finish_spec.rb +94 -0
  35. data/spec/unit/js_spec/resources/suite_spec.rb +44 -0
  36. data/spec/unit/js_spec/resources/web_root_spec.rb +67 -0
  37. data/spec/unit/js_spec/server_spec.rb +131 -0
  38. data/spec/unit/thin/js_test_core_connection_spec.rb +92 -0
  39. data/spec/unit/unit_spec_helper.rb +125 -0
  40. data/spec/unit_suite.rb +10 -0
  41. metadata +113 -0
@@ -0,0 +1,17 @@
1
+ module JsTestCore
2
+ module Resources
3
+ module Specs
4
+ class SpecFileSuperclass < ::JsTestCore::Resources::File
5
+ def get(request, response)
6
+ raise NotImplementedError, "#{self.class}#get needs to be implemented"
7
+ end
8
+ end
9
+
10
+ class SpecFile < SpecFileSuperclass
11
+ def spec_files
12
+ [self]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ module JsTestCore
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
@@ -0,0 +1,19 @@
1
+ module JsTestCore
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
+ if suite.id == 'user'
11
+ STDOUT.puts request['text']
12
+ else
13
+ Runners::FirefoxRunner.resume(suite.id, request['text'])
14
+ end
15
+ response.headers['Content-Length'] = "0"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class WebRoot
4
+ LOCATIONS = [
5
+ ['core', lambda do
6
+ Resources::Dir.new(JsTestCore::Server.core_path, "/core")
7
+ end],
8
+ ['implementations', lambda do
9
+ Resources::Dir.new(JsTestCore::Server.implementation_root_path, "/implementations")
10
+ end],
11
+ ['suites', lambda do
12
+ Resources::Suite
13
+ end],
14
+ ['runners', lambda do
15
+ Resources::Runners.new
16
+ end]
17
+ ]
18
+
19
+ class << self
20
+ attr_accessor :dispatch_strategy
21
+ def dispatch_specs
22
+ self.dispatch_strategy = :specs
23
+ end
24
+ end
25
+
26
+ attr_reader :public_path
27
+ def initialize(public_path)
28
+ @public_path = ::File.expand_path(public_path)
29
+ end
30
+
31
+ def locate(name)
32
+ if self.class.dispatch_strategy == :specs && name == 'specs'
33
+ return JsTestCore::Resources::Specs::SpecDir.new(JsTestCore::Server.spec_root_path, "/specs")
34
+ end
35
+
36
+ location, initializer = LOCATIONS.find do |location|
37
+ location.first == name
38
+ end
39
+ if initializer
40
+ initializer.call
41
+ else
42
+ potential_file_in_public_path = "#{public_path}/#{name}"
43
+ if ::File.directory?(potential_file_in_public_path)
44
+ Resources::Dir.new(potential_file_in_public_path, "/#{name}")
45
+ elsif ::File.exists?(potential_file_in_public_path)
46
+ Resources::File.new(potential_file_in_public_path, "/#{name}")
47
+ else
48
+ raise "Invalid path: #{name}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/selenium/selenium_driver"
@@ -0,0 +1,5 @@
1
+ module Selenium
2
+ class SeleniumDriver
3
+ attr_reader :session_id
4
+ end
5
+ end
@@ -0,0 +1,111 @@
1
+ module JsTestCore
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 test_dir_class; instance.test_dir_class; end
18
+ def test_file_class; instance.test_file_class; end
19
+ def connection; instance.connection; end
20
+ def request; instance.request; end
21
+ def response; instance.response; end
22
+ def root_url; instance.root_url; end
23
+ end
24
+
25
+ attr_reader :host, :port, :spec_root_path, :implementation_root_path, :public_path
26
+
27
+ def initialize(spec_root_path, implementation_root_path, public_path, host=DEFAULT_HOST, port=DEFAULT_PORT)
28
+ dir = ::File.dirname(__FILE__)
29
+ @spec_root_path = ::File.expand_path(spec_root_path)
30
+ @implementation_root_path = ::File.expand_path(implementation_root_path)
31
+ @public_path = ::File.expand_path(public_path)
32
+ @host = host
33
+ @port = port
34
+ end
35
+
36
+ def run(options)
37
+ server = ::Thin::Server.new(options[:Host], options[:Port], self)
38
+ server.backend = ::Thin::Backends::JsTestCoreServer.new(options[:Host], options[:Port])
39
+ server.backend.server = server
40
+ server.start!
41
+ end
42
+
43
+ def call(env)
44
+ self.connection = env['js_test_core.connection']
45
+ self.request = Rack::Request.new(env)
46
+ self.response = Rack::Response.new
47
+ method = request.request_method.downcase.to_sym
48
+ get_resource(request).send(method, request, response)
49
+ response.finish
50
+ ensure
51
+ self.connection = nil
52
+ self.request = nil
53
+ self.response = nil
54
+ end
55
+
56
+ def connection
57
+ Thread.current[:connection]
58
+ end
59
+
60
+ def request
61
+ Thread.current[:request]
62
+ end
63
+
64
+ def response
65
+ Thread.current[:response]
66
+ end
67
+
68
+ def root_url
69
+ "http://#{host}:#{port}"
70
+ end
71
+
72
+ def core_path
73
+ JsTestCore.core_path
74
+ end
75
+
76
+ def test_dir_class
77
+ JsTestCore.adapter.test_dir_class
78
+ end
79
+
80
+ def test_file_class
81
+ JsTestCore.adapter.test_file_class
82
+ end
83
+
84
+ protected
85
+ def connection=(connection)
86
+ Thread.current[:connection] = connection
87
+ end
88
+
89
+ def request=(request)
90
+ Thread.current[:request] = request
91
+ end
92
+
93
+ def response=(response)
94
+ Thread.current[:response] = response
95
+ end
96
+
97
+ def path_parts(req)
98
+ request.path_info.split('/').reject { |part| part == "" }
99
+ end
100
+
101
+ def get_resource(request)
102
+ path_parts(request).inject(Resources::WebRoot.new(public_path)) do |resource, child_resource_name|
103
+ resource.locate(child_resource_name)
104
+ end
105
+ rescue Exception => e
106
+ detailed_exception = Exception.new("Error handling path #{request.path_info}\n#{e.message}")
107
+ detailed_exception.set_backtrace(e.backtrace)
108
+ raise detailed_exception
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/thin/js_test_core_connection"
3
+ require "#{dir}/thin/backends/js_test_core_server"
@@ -0,0 +1,9 @@
1
+ module Thin
2
+ module Backends
3
+ class JsTestCoreServer < TcpServer
4
+ def connect
5
+ @signature = EventMachine.start_server(@host, @port, JsTestCoreConnection, &method(:initialize_connection))
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module Thin
2
+ class JsTestCoreConnection < 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_test_core.connection'] = self
9
+ @response.status, @response.headers, @response.body = @app.call(env)
10
+ send_data @response.head
11
+ if !@response.body.empty? || @response.headers.to_s.include?("Content-Length: 0")
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
@@ -0,0 +1,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ raise "Failure" unless system(%Q|ruby #{dir}/unit_suite.rb|)
@@ -0,0 +1,137 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ describe Client do
5
+ describe '.run' do
6
+ describe 'when successful' do
7
+ before do
8
+ request = Object.new
9
+ mock(request).post("/runners/firefox", "selenium_host=localhost&selenium_port=4444")
10
+ response = Object.new
11
+ mock(response).body {""}
12
+ mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
13
+ stub(Client).puts
14
+ end
15
+
16
+ it "returns true" do
17
+ Client.run.should be_true
18
+ end
19
+
20
+ it "prints 'SUCCESS'" do
21
+ mock(Client).puts("SUCCESS")
22
+ Client.run
23
+ end
24
+ end
25
+
26
+ describe 'when unsuccessful' do
27
+ before do
28
+ request = Object.new
29
+ mock(request).post("/runners/firefox", "selenium_host=localhost&selenium_port=4444")
30
+ response = Object.new
31
+ mock(response).body {"the failure message"}
32
+ mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
33
+ stub(Client).puts
34
+ end
35
+
36
+ it "returns false" do
37
+ Client.run.should be_false
38
+ end
39
+
40
+ it "prints 'FAILURE' and the error message(s)" do
41
+ mock(Client).puts("FAILURE")
42
+ mock(Client).puts("the failure message")
43
+ Client.run
44
+ end
45
+ end
46
+
47
+ describe "arguments" do
48
+ attr_reader :request, :response
49
+ before do
50
+ @request = Object.new
51
+ @response = Object.new
52
+ mock(response).body {""}
53
+ mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
54
+ stub(Client).puts
55
+ end
56
+
57
+ describe "when passed a custom spec_url" do
58
+ it "passes the spec_url as a post parameter" do
59
+ spec_url = 'http://foobar.com/foo'
60
+ mock(request).post(
61
+ "/runners/firefox",
62
+ "selenium_host=localhost&selenium_port=4444&spec_url=#{CGI.escape(spec_url)}"
63
+ )
64
+ Client.run(:spec_url => spec_url)
65
+ end
66
+ end
67
+
68
+ describe "when passed a custom selenium host" do
69
+ it "passes the selenium_host as a post parameter" do
70
+ selenium_host = 'test-runner'
71
+ mock(request).post(
72
+ "/runners/firefox",
73
+ "selenium_host=test-runner&selenium_port=4444"
74
+ )
75
+ Client.run(:selenium_host => selenium_host)
76
+ end
77
+ end
78
+
79
+ describe "when passed a custom selenium port" do
80
+ it "passes the selenium_port as a post parameter" do
81
+ selenium_port = 5000
82
+ mock(request).post(
83
+ "/runners/firefox",
84
+ "selenium_host=localhost&selenium_port=5000"
85
+ )
86
+ Client.run(:selenium_port => selenium_port)
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ describe ".run_argv" do
94
+ attr_reader :request, :response
95
+ before do
96
+ @request = Object.new
97
+ @response = Object.new
98
+ mock(response).body {""}
99
+ mock(Net::HTTP).start(DEFAULT_HOST, DEFAULT_PORT).yields(request) {response}
100
+ stub(Client).puts
101
+ end
102
+
103
+ describe "when passed a custom spec_url" do
104
+ it "passes the spec_url as a post parameter" do
105
+ spec_url = 'http://foobar.com/foo'
106
+ mock(request).post(
107
+ "/runners/firefox",
108
+ "selenium_host=localhost&selenium_port=4444&spec_url=#{CGI.escape(spec_url)}"
109
+ )
110
+ Client.run_argv(['--spec_url', spec_url])
111
+ end
112
+ end
113
+
114
+ describe "when passed a custom selenium host" do
115
+ it "passes the selenium_host as a post parameter" do
116
+ selenium_host = 'test-runner'
117
+ mock(request).post(
118
+ "/runners/firefox",
119
+ "selenium_host=test-runner&selenium_port=4444"
120
+ )
121
+ Client.run_argv(['--selenium_host', selenium_host])
122
+ end
123
+ end
124
+
125
+ describe "when passed a custom selenium port" do
126
+ it "passes the selenium_port as a post parameter" do
127
+ selenium_port = 5000
128
+ mock(request).post(
129
+ "/runners/firefox",
130
+ "selenium_host=localhost&selenium_port=5000"
131
+ )
132
+ Client.run_argv(['--selenium_port', selenium_port.to_s])
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../unit_spec_helper")
2
+
3
+ module JsTestCore
4
+ describe RailsServer do
5
+ it "subclasses Server" do
6
+ RailsServer.superclass.should == Server
7
+ end
8
+
9
+ describe ".run" do
10
+ attr_reader :rails_root
11
+ before do
12
+ @rails_root = "/rails/root"
13
+ Server.instance = nil
14
+ end
15
+
16
+ it "initializes the RailsServer and runs the Thin Handler and sets Server.instance to the RailsServer instance" do
17
+ host = DEFAULT_HOST
18
+ port = DEFAULT_PORT
19
+ server_instance = nil
20
+ mock.proxy(RailsServer).new(
21
+ rails_root,
22
+ host,
23
+ port
24
+ ) do |new_instance|
25
+ server_instance = new_instance
26
+ end
27
+
28
+ mock(EventMachine).run.yields
29
+ mock(EventMachine).start_server(host, port, ::Thin::JsTestCoreConnection)
30
+ RailsServer.run(rails_root)
31
+ Server.instance.should == server_instance
32
+ end
33
+ end
34
+
35
+ describe "#initialize" do
36
+ it "sets the server paths based on the passed in rails root" do
37
+ rails_root = "/rails/root"
38
+ server = RailsServer.new(rails_root)
39
+ server.spec_root_path.should == "#{rails_root}/spec/javascripts"
40
+ server.implementation_root_path.should == "#{rails_root}/public/javascripts"
41
+ server.public_path.should == "#{rails_root}/public"
42
+ end
43
+ end
44
+ end
45
+ end