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
data/CHANGES ADDED
@@ -0,0 +1,9 @@
1
+ 0.1.1
2
+ - SuiteFinish#post immediately closes the connection
3
+
4
+ 0.1.0
5
+ - Initial Release extracted from JsTestCore.
6
+ - Added JsTestCore::WebRoot.dispatch_specs and .dispatch_strategy
7
+ - Extracted JsTestCore::Resources::Specs::SpecDir
8
+ - Extracted JsTestCore::Resources::Specs::SpecFile
9
+ - No longer depending on Guid. The child libraries are responsible for obtaining the Selenium session_id from the client by using top.runOptions.getSessionId().
data/README ADDED
@@ -0,0 +1,12 @@
1
+ = JsTestCore
2
+ The JsTestCore library is the core javascript test server library used by several JS Test server libraries.
3
+
4
+ To hook up your own JS Test framework:
5
+ * You will need to call either JsTestCore::Resources::WebRoot.dispatch_specs or JsTestCore::Resources::WebRoot.dispatch_tests
6
+ depending if you are serving specs or tests.
7
+ * Set JsTestCore.core_path to the directory of the client side test framework (javascript files)
8
+ * Override JsTestCore::Resources::Specs::SpecFile#get or JsTestCore::Resources::Specs::TestFile#get
9
+ * Override JsTestCore::Resources::Specs::SpecDir#get or JsTestCore::Resources::Specs::TestDir#get
10
+
11
+ NOTE: The current version of JsTestCore does not yet support tests. Support will be added soon.
12
+ I just wanted the test stuff to be in the docs to establish the current architectural direction.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ require "rake"
2
+ require 'rake/gempackagetask'
3
+ require 'rake/contrib/rubyforgepublisher'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+
8
+ desc "Runs the Rspec suite"
9
+ task(:default) do
10
+ run_suite
11
+ end
12
+
13
+ desc "Runs the Rspec suite"
14
+ task(:spec) do
15
+ run_suite
16
+ end
17
+
18
+ desc "Copies the trunk to a tag with the name of the current release"
19
+ task(:tag_release) do
20
+ tag_release
21
+ end
22
+
23
+ def run_suite
24
+ dir = File.dirname(__FILE__)
25
+ system("ruby #{dir}/spec/spec_suite.rb") || raise("Example Suite failed")
26
+ end
27
+
28
+ PKG_NAME = "js_test_core"
29
+ PKG_VERSION = "0.1.1"
30
+ PKG_FILES = FileList[
31
+ '[A-Z]*',
32
+ '*.rb',
33
+ 'lib/**/*.rb',
34
+ 'core/**',
35
+ 'bin/**',
36
+ 'spec/**/*.rb'
37
+ ]
38
+
39
+ spec = Gem::Specification.new do |s|
40
+ s.name = PKG_NAME
41
+ s.version = PKG_VERSION
42
+ s.summary = "The JsTestCore library is the core javascript test server library used by several JS Test server libraries."
43
+ s.test_files = "spec/spec_suite.rb"
44
+ s.description = s.summary
45
+
46
+ s.files = PKG_FILES.to_a
47
+ s.require_path = 'lib'
48
+
49
+ s.has_rdoc = true
50
+ s.extra_rdoc_files = [ "README", "CHANGES" ]
51
+ s.rdoc_options = ["--main", "README", "--inline-source", "--line-numbers"]
52
+
53
+ s.test_files = Dir.glob('spec/*_spec.rb')
54
+ s.require_path = 'lib'
55
+ s.author = "Brian Takita"
56
+ s.email = "brian@pivotallabs.com"
57
+ s.homepage = "http://pivotallabs.com"
58
+ s.rubyforge_project = "pivotalrb"
59
+ s.add_dependency('Selenium')
60
+ s.add_dependency('thin', '=0.8.1')
61
+ end
62
+
63
+ Rake::GemPackageTask.new(spec) do |pkg|
64
+ pkg.need_zip = true
65
+ pkg.need_tar = true
66
+ end
67
+
68
+ def tag_release
69
+ dashed_version = PKG_VERSION.gsub('.', '-')
70
+ svn_user = "#{ENV["SVN_USER"]}@" || ""
71
+ `svn cp svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/js_test_core/trunk svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/js_test_core/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
72
+ end
@@ -0,0 +1,30 @@
1
+ require "rubygems"
2
+ gem "thin", ">=0.8.0"
3
+
4
+ require "thin"
5
+ require "fileutils"
6
+ require "tmpdir"
7
+ require "timeout"
8
+ require "cgi"
9
+ require "net/http"
10
+ require "selenium"
11
+ require "optparse"
12
+
13
+ dir = File.dirname(__FILE__)
14
+ require "#{dir}/js_test_core/thin"
15
+ require "#{dir}/js_test_core/rack"
16
+ require "#{dir}/js_test_core/resources"
17
+ require "#{dir}/js_test_core/selenium"
18
+
19
+ require "#{dir}/js_test_core/client"
20
+ require "#{dir}/js_test_core/server"
21
+ require "#{dir}/js_test_core/rails_server"
22
+
23
+ module JsTestCore
24
+ DEFAULT_HOST = "0.0.0.0"
25
+ DEFAULT_PORT = 8080
26
+
27
+ class << self
28
+ attr_accessor :core_path
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ module JsTestCore
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 = "JsTestCore 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
@@ -0,0 +1,2 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/rack/commonlogger"
@@ -0,0 +1,5 @@
1
+ Rack::CommonLogger.class_eval do
2
+ def empty?
3
+ @body.empty?
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module JsTestCore
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
@@ -0,0 +1,10 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/resources/runners"
3
+ require "#{dir}/resources/runners/firefox_runner"
4
+ require "#{dir}/resources/file"
5
+ require "#{dir}/resources/dir"
6
+ require "#{dir}/resources/specs/spec_file"
7
+ require "#{dir}/resources/specs/spec_dir"
8
+ require "#{dir}/resources/web_root"
9
+ require "#{dir}/resources/suite"
10
+ require "#{dir}/resources/suite_finish"
@@ -0,0 +1,52 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Dir < File
4
+ def locate(name)
5
+ if file = file(name)
6
+ file
7
+ elsif subdir = subdir(name)
8
+ subdir
9
+ else
10
+ raise "No file or directory found at #{relative_path}/#{name}."
11
+ end
12
+ end
13
+
14
+ def get(request, response)
15
+
16
+ end
17
+
18
+ def glob(pattern)
19
+ expanded_pattern = absolute_path + pattern
20
+ ::Dir.glob(expanded_pattern).map do |absolute_globbed_path|
21
+ relative_globbed_path = absolute_globbed_path.gsub(absolute_path, relative_path)
22
+ File.new(absolute_globbed_path, relative_globbed_path)
23
+ end
24
+ end
25
+
26
+ protected
27
+ def determine_child_paths(name)
28
+ absolute_child_path = "#{absolute_path}/#{name}"
29
+ relative_child_path = "#{relative_path}/#{name}"
30
+ [absolute_child_path, relative_child_path]
31
+ end
32
+
33
+ def file(name)
34
+ absolute_file_path, relative_file_path = determine_child_paths(name)
35
+ if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
36
+ Resources::File.new(absolute_file_path, relative_file_path)
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ def subdir(name)
43
+ absolute_dir_path, relative_dir_path = determine_child_paths(name)
44
+ if ::File.directory?(absolute_dir_path)
45
+ Resources::Dir.new(absolute_dir_path, relative_dir_path)
46
+ else
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ module JsTestCore
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
@@ -0,0 +1,15 @@
1
+ dir = File.dirname(__FILE__)
2
+
3
+ module JsTestCore
4
+ module Resources
5
+ class Runners
6
+ def locate(name)
7
+ if name == 'firefox'
8
+ FirefoxRunner.new
9
+ else
10
+ raise "Invalid path #{name}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,73 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Runners
4
+ class FirefoxRunner
5
+ class << self
6
+ def resume(suite_id, text)
7
+ runner = instances.delete(suite_id)
8
+ runner.finalize(text)
9
+ end
10
+
11
+ def register_instance(runner)
12
+ instances[runner.suite_id] = runner
13
+ end
14
+
15
+ protected
16
+ def instances
17
+ @instances ||= {}
18
+ end
19
+ end
20
+
21
+ include FileUtils
22
+ attr_reader :profile_dir, :connection, :driver, :response
23
+
24
+ def initialize
25
+ profile_base = "#{::Dir.tmpdir}/js_test_core/firefox"
26
+ mkdir_p profile_base
27
+ @profile_dir = "#{profile_base}/#{Time.now.to_i}"
28
+ @connection = Server.connection
29
+ end
30
+
31
+ def post(request, response)
32
+ @response = response
33
+
34
+ spec_url = (request && request['spec_url']) ? request['spec_url'] : spec_suite_url
35
+ parsed_spec_url = URI.parse(spec_url)
36
+ selenium_port = (request['selenium_port'] || 4444).to_i
37
+ @driver = Selenium::SeleniumDriver.new(
38
+ request['selenium_host'] || 'localhost',
39
+ selenium_port,
40
+ '*firefox',
41
+ "#{parsed_spec_url.scheme}://#{parsed_spec_url.host}:#{parsed_spec_url.port}"
42
+ )
43
+ begin
44
+ driver.start
45
+ rescue Errno::ECONNREFUSED => e
46
+ raise Errno::ECONNREFUSED, "Cannot connect to Selenium Server on port #{selenium_port}. To start the selenium server, run `selenium`."
47
+ end
48
+ Thread.start do
49
+ driver.open(spec_url)
50
+ end
51
+ response.status = 200
52
+ FirefoxRunner.register_instance self
53
+ end
54
+
55
+ def finalize(text)
56
+ driver.stop
57
+ response.body = text
58
+ connection.send_body(response)
59
+ end
60
+
61
+ def suite_id
62
+ driver.session_id
63
+ end
64
+
65
+ protected
66
+
67
+ def spec_suite_url
68
+ "#{Server.root_url}/specs"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,50 @@
1
+ module JsTestCore
2
+ module Resources
3
+ module Specs
4
+ class SpecDirSuperclass < ::JsTestCore::Resources::Dir
5
+ def get(request, response)
6
+ raise NotImplementedError, "#{self.class}#get needs to be implemented"
7
+ end
8
+ end
9
+
10
+ class SpecDir < SpecDirSuperclass
11
+ def spec_files
12
+ glob("/**/*_spec.js")
13
+ end
14
+
15
+ def locate(name)
16
+ if file = file(name)
17
+ file
18
+ elsif subdir = subdir(name)
19
+ subdir
20
+ elsif spec_file = spec_file(name)
21
+ spec_file
22
+ else
23
+ base_path = "#{relative_path}/#{name}"
24
+ raise "No file or directory found at #{base_path} or spec found at #{base_path}.js."
25
+ end
26
+ end
27
+
28
+ protected
29
+
30
+ def subdir(name)
31
+ absolute_dir_path, relative_dir_path = determine_child_paths(name)
32
+ if ::File.directory?(absolute_dir_path)
33
+ SpecDir.new(absolute_dir_path, relative_dir_path)
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ def spec_file(name)
40
+ absolute_file_path, relative_file_path = determine_child_paths("#{name}.js")
41
+ if ::File.exists?(absolute_file_path) && !::File.directory?(absolute_file_path)
42
+ SpecFile.new(absolute_file_path, relative_file_path)
43
+ else
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end