steam 0.0.2

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.
Files changed (62) hide show
  1. data/MIT-LICENSE +21 -0
  2. data/README.textile +91 -0
  3. data/Rakefile +23 -0
  4. data/TODO +7 -0
  5. data/lib/core_ext/ruby/array/flatten_once.rb +9 -0
  6. data/lib/core_ext/ruby/hash/except.rb +11 -0
  7. data/lib/core_ext/ruby/hash/slice.rb +14 -0
  8. data/lib/core_ext/ruby/kernel/silence_warnings.rb +8 -0
  9. data/lib/core_ext/ruby/process/daemon.rb +23 -0
  10. data/lib/core_ext/ruby/string/camelize.rb +5 -0
  11. data/lib/core_ext/ruby/string/underscore.rb +5 -0
  12. data/lib/steam.rb +43 -0
  13. data/lib/steam/browser.rb +24 -0
  14. data/lib/steam/browser/html_unit.rb +87 -0
  15. data/lib/steam/browser/html_unit/actions.rb +176 -0
  16. data/lib/steam/browser/html_unit/client.rb +74 -0
  17. data/lib/steam/browser/html_unit/connection.rb +79 -0
  18. data/lib/steam/browser/html_unit/drb.rb +45 -0
  19. data/lib/steam/browser/html_unit/matchers.rb +57 -0
  20. data/lib/steam/browser/html_unit/page.rb +51 -0
  21. data/lib/steam/browser/html_unit/web_response.rb +116 -0
  22. data/lib/steam/connection.rb +9 -0
  23. data/lib/steam/connection/mock.rb +57 -0
  24. data/lib/steam/connection/net_http.rb +42 -0
  25. data/lib/steam/connection/open_uri.rb +24 -0
  26. data/lib/steam/connection/rails.rb +20 -0
  27. data/lib/steam/connection/static.rb +33 -0
  28. data/lib/steam/java.rb +74 -0
  29. data/lib/steam/process.rb +53 -0
  30. data/lib/steam/request.rb +49 -0
  31. data/lib/steam/response.rb +13 -0
  32. data/lib/steam/session.rb +30 -0
  33. data/lib/steam/session/rails.rb +33 -0
  34. data/lib/steam/version.rb +3 -0
  35. data/test/all.rb +3 -0
  36. data/test/browser/html_unit/actions_test.rb +183 -0
  37. data/test/browser/html_unit/javascript_test.rb +60 -0
  38. data/test/browser/html_unit/rails_actions_test.rb +151 -0
  39. data/test/browser/html_unit_test.rb +97 -0
  40. data/test/connection/cascade_test.rb +42 -0
  41. data/test/connection/mock_test.rb +58 -0
  42. data/test/connection/rails_test.rb +16 -0
  43. data/test/connection/static_test.rb +14 -0
  44. data/test/fixtures/html_fakes.rb +191 -0
  45. data/test/java_test.rb +29 -0
  46. data/test/playground/connection.rb +19 -0
  47. data/test/playground/dragdrop_behavior.rb +60 -0
  48. data/test/playground/drb.rb +55 -0
  49. data/test/playground/java_signature.rb +22 -0
  50. data/test/playground/nokogiri.rb +15 -0
  51. data/test/playground/put_headers.rb +83 -0
  52. data/test/playground/rack.rb +11 -0
  53. data/test/playground/rjb_bind.rb +42 -0
  54. data/test/playground/stack_level_problem.rb +129 -0
  55. data/test/playground/thread_problem.rb +57 -0
  56. data/test/playground/web_response_data.rb +21 -0
  57. data/test/playground/webrat.rb +48 -0
  58. data/test/playground/xhr_accept_headers.rb +61 -0
  59. data/test/process_test.rb +55 -0
  60. data/test/session_test.rb +15 -0
  61. data/test/test_helper.rb +56 -0
  62. metadata +135 -0
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+
4
+ class JavaTest < Test::Unit::TestCase
5
+ include Steam
6
+ include Java::AutoDefine
7
+ extend Java::AutoDefine
8
+
9
+ test "pop_name" do
10
+ name = 'A::B::C'
11
+ assert 'A', pop_name(name)
12
+ assert 'B', pop_name(name)
13
+ assert 'C', pop_name(name)
14
+ end
15
+
16
+ test "const_set_nested" do
17
+ const = self.class.const_set_nested('A::B::C', Module.new)
18
+ assert_equal A::B::C, const
19
+ end
20
+
21
+ test "java_path_to_const_name" do
22
+ assert_equal 'Util::ArrayList', Java.path_to_const_name("java.util.ArrayList")
23
+ end
24
+
25
+ test "import" do
26
+ const = Java.import('java.util.Set')
27
+ assert_equal Java::Util::Set, const
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + "/../../lib")
2
+ require 'steam'
3
+ include Steam
4
+
5
+ Java.import 'com.gargoylesoftware.htmlunit.WebClient'
6
+ Java.import 'com.gargoylesoftware.htmlunit.BrowserVersion'
7
+
8
+ client = Java::WebClient.new(Java::BrowserVersion.FIREFOX_3)
9
+ client.setCssEnabled(true)
10
+ client.setJavaScriptEnabled(true)
11
+
12
+ mock = Connection::Mock.new
13
+ mock.mock :get, 'http://localhost:3000/', 'body!'
14
+
15
+ connection = Browser::HtmlUnit::Connection.new(mock)
16
+ client.setWebConnection(Rjb::bind(connection, 'com.gargoylesoftware.htmlunit.WebConnection'))
17
+
18
+ page = client.getPage('http://localhost:3000/')
19
+ puts page.asXml
@@ -0,0 +1,60 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'steam'
4
+
5
+ include Steam
6
+
7
+ Steam.config[:html_unit][:java_path] = File.expand_path("../../lib/htmlunit-2.7/", __FILE__)
8
+
9
+ @app = Connection::Mock.new
10
+ root = File.expand_path("../fixtures/public", __FILE__)
11
+ static = Connection::Static.new(:root => root, :urls => %w(/ /javascripts /stylesheets))
12
+ @browser = Browser::HtmlUnit.new(Rack::Cascade.new([static, @app]))
13
+
14
+ def drag_to(target)
15
+ @browser.page.executeJavaScript('$("#log").text("")')
16
+
17
+ drag = @browser.locate_in_browser(:div, :class => 'drag')
18
+ drop = @browser.locate_in_browser(:div, :id => target)
19
+
20
+ puts "\nDRAGGING #{drag.getCanonicalXPath}"
21
+ puts "DROPPING ONTO:\n" + drop.asXml # (#{drop.getCanonicalXPath})
22
+
23
+ drag.mouseDown
24
+ drop.mouseMove
25
+ page = drop.mouseUp
26
+
27
+ log = page.executeJavaScript('$("#log").text()').getJavaScriptResult
28
+ puts "RECEIVED DROP EVENT ON:\n" + log.toString
29
+ end
30
+
31
+ @browser.request('/index.html')
32
+ drag_to('drop_1')
33
+ drag_to('drop_2')
34
+ drag_to('drop_3')
35
+ # drag_to('drop_4')
36
+ # drag_to('drop_5')
37
+ # drag_to('drop_6')
38
+
39
+ # OUTPUT:
40
+ #
41
+ # DROPPING ONTO (/html/body/div[2]):
42
+ # <div class="drop ui-droppable" id="drop_2">
43
+ # </div>
44
+ # RECEIVED DROP EVENT ON:
45
+ # <div id="drop_1" class="drop ui-droppable"></div>
46
+ #
47
+ # DROPPING ONTO (/html/body/div[3]):
48
+ # <div class="drop ui-droppable" id="drop_3">
49
+ # </div>
50
+ # RECEIVED DROP EVENT ON:
51
+ # <div id="drop_2" class="drop ui-droppable"></div>
52
+ #
53
+ # DROPPING ONTO (/html/body/div[4]):
54
+ # <div class="drop ui-droppable" id="drop_4">
55
+ # </div>
56
+ # RECEIVED DROP EVENT ON:
57
+ # <div id="drop_3" class="drop ui-droppable"></div>
58
+
59
+
60
+
@@ -0,0 +1,55 @@
1
+ $: << File.expand_path("../../../lib", __FILE__)
2
+
3
+ require 'steam'
4
+ require 'drb'
5
+
6
+ include Steam
7
+
8
+ # # using a static connection works /w drb
9
+ # root = File.expand_path("../../fixtures/public", __FILE__)
10
+ # connection = Connection::Static.new(:root => root, :urls => ['/'])
11
+ #
12
+ # # using a mocked connection works /w drb
13
+ # connection = Connection::Mock.new
14
+ # connection.mock 'http://localhost:3000/short.html', <<-html
15
+ # <html>
16
+ # <head>
17
+ # <script src="/title.js" type="text/javascript"></script>
18
+ # <script src="/jquery-ui-1.8rc1.js" type="text/javascript"></script>
19
+ # </head>
20
+ # </html>
21
+ # html
22
+ # connection.mock 'http://localhost:3000/title.js', "document.title = 'FOO'"
23
+ # connection.mock 'http://localhost:3000/jquery-ui-1.8rc1.js', File.read('test/fixtures/public/jquery-ui-1.8rc1.js')
24
+
25
+ # # Using the native default connection, i.e. connecting over the network, does
26
+ # # not work /w drb when the first response has to retrieve additional assets,
27
+ # # like a js file. (There's a config.ru file in test/, so one can rackup the
28
+ # # files in test/fixtures/public.)
29
+ connection = nil
30
+
31
+ # Interestingly, this works in all situations, except that it does not implement
32
+ # a full REST interface and I don't want to implement a cookie jar and everything
33
+ # connection = Connection::OpenUri.new
34
+
35
+
36
+ # url = 'http://localhost:3000/short.html'
37
+ url = 'http://localhost:3000'
38
+
39
+ def request_without_drb(browser, url)
40
+ browser.request(url)
41
+ browser.response
42
+ end
43
+
44
+ def request_with_drb(browser, url)
45
+ DRb.start_service(Steam.config[:drb_uri], browser)
46
+ drb = DRbObject.new(nil, Steam.config[:drb_uri])
47
+ drb.request(url)
48
+ drb.response
49
+ end
50
+
51
+ browser = Steam::Browser.create(:html_unit, connection)
52
+ response = request_without_drb(browser, url)
53
+ # response = request_with_drb(browser, url)
54
+
55
+ puts response.body
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'rjb'
3
+
4
+ class_path = Dir[File.expand_path(File.dirname(__FILE__) + '/../../lib/htmlunit') + '/*.jar'].join(':')
5
+ Rjb::load(class_path)
6
+
7
+
8
+ klass = Rjb::import('java.lang.String')
9
+ klass = Rjb::import('com.gargoylesoftware.htmlunit.WebResponseData')
10
+
11
+ # methods = klass.getDeclaredMethods
12
+ methods = klass.getConstructors
13
+
14
+ methods.each do |method|
15
+ # method.getParameterTypes.map { |type| p type._classname }
16
+ params = method.getParameterTypes.map { |type| type.getName }.join(', ')
17
+ puts "#{method.getName}(#{params})"
18
+ end
19
+
20
+ signature = '[B'
21
+ p klass.new_with_sig(signature, "foo".split(/./))
22
+ # String(byte[] bytes)
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+
4
+ html = <<-html
5
+ <html>
6
+ <body>
7
+ <p class="foo bar baz">FOO</p>
8
+ </body>
9
+ </html>
10
+ html
11
+
12
+ # p Nokogiri::CSS.xpath_for('p[content="FOO"]')
13
+ doc = Nokogiri::HTML::Document.parse(html)
14
+ p doc.css('p[class~="foo"]', 'FOO')
15
+ # p doc.xpath('//p')
@@ -0,0 +1,83 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + "/../../lib")
2
+ require 'test/unit'
3
+ require 'steam'
4
+ include Steam
5
+
6
+ Java.import 'com.gargoylesoftware.htmlunit.WebClient'
7
+ Java.import 'com.gargoylesoftware.htmlunit.BrowserVersion'
8
+ Java.import 'com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException'
9
+ Java.import 'com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController'
10
+
11
+ SILENCE = true
12
+
13
+ class TestConnection < Browser::HtmlUnit::Connection
14
+ attr_reader :url, :method, :headers
15
+
16
+ def getResponse(request)
17
+ @url = request.getUrl.toString
18
+ # $method = request.getMethod.toString
19
+ @headers = Hash[*request.getAdditionalHeaders.entrySet.toArray.to_a.map do |a|
20
+ [a.getKey.toString, a.getValue.toString]
21
+ end.flatten]
22
+ super
23
+ end
24
+ end
25
+
26
+ class TestHtmlUnit < Test::Unit::TestCase
27
+ def setup
28
+ @client = Java::WebClient.new(Java::BrowserVersion.FIREFOX_3)
29
+ @client.setCssEnabled(true)
30
+ @client.setJavaScriptEnabled(true)
31
+ # client.setAjaxController(Java::NicelyResynchronizingAjaxController.new)
32
+
33
+ @mock = Connection::Mock.new
34
+ @connection = TestConnection.new(@mock)
35
+ @client.setWebConnection(Rjb::bind(@connection, 'com.gargoylesoftware.htmlunit.WebConnection'))
36
+ end
37
+
38
+ def _test_xml_http_request_accept_header
39
+ page = <<-erb
40
+ <html>
41
+ <head>
42
+ <script>
43
+ document.title = 'pre ajax call';
44
+ function ajax(url) {
45
+ http = new XMLHttpRequest();
46
+ http.open("GET", url, true);
47
+ http.setRequestHeader('Accept', 'application/json')
48
+ http.send(null);
49
+ }
50
+ ajax('/ajax/1');
51
+ </script>
52
+ </head>
53
+ </html>
54
+ erb
55
+
56
+ @mock.mock :get, 'http://localhost:3000/', page
57
+ page = @client.getPage('http://localhost:3000/')
58
+ assert_equal 'application/json', @connection.headers['Accept']
59
+ end
60
+
61
+ def test_xml_http_request_delete_query_params
62
+ page = <<-erb
63
+ <html>
64
+ <head>
65
+ <script>
66
+ document.title = 'pre ajax call';
67
+ function ajax(url) {
68
+ http = new XMLHttpRequest();
69
+ http.open("DELETE", url, true);
70
+ http.setRequestHeader('Accept', 'application/json')
71
+ http.send(null);
72
+ }
73
+ ajax('/ajax/1?foo=bar');
74
+ </script>
75
+ </head>
76
+ </html>
77
+ erb
78
+
79
+ @mock.mock :get, 'http://localhost:3000/', page
80
+ page = @client.getPage('http://localhost:3000/')
81
+ assert_equal 'http://localhost:3000/ajax/1?foo=bar', @connection.url
82
+ end
83
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rack'
3
+ require 'rack/file'
4
+ require 'rack/mock'
5
+
6
+ include Rack
7
+
8
+ rack = File.new(File.dirname(__FILE__) + '/fixtures')
9
+ env = MockRequest.env_for('http://localhost:3000/javascripts/foo.js')
10
+ response = rack.call(env)
11
+ p response[2].path
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'rjb'
3
+
4
+ class_path = Dir[File.expand_path(File.dirname(__FILE__) + '/../../lib/htmlunit') + '/*.jar'].join(':')
5
+
6
+ Rjb::load(class_path)
7
+
8
+ Url = Rjb::import('java.net.URL')
9
+ WebClient = Rjb::import('com.gargoylesoftware.htmlunit.WebClient')
10
+ HtmlUnitMockWebConnection = Rjb::import('com.gargoylesoftware.htmlunit.MockWebConnection')
11
+
12
+ class MockConnection
13
+ attr_reader :connection
14
+
15
+ def initialize
16
+ @connection = HtmlUnitMockWebConnection.new
17
+ end
18
+
19
+ def method_missing(method, *args)
20
+ p [method, args.first.toString]
21
+ @connection.send(method, *args)
22
+ end
23
+ end
24
+
25
+ connection = MockConnection.new
26
+ # connection = HtmlUnitMockWebConnection.new
27
+
28
+ content = '<html><head><script src="/javascripts/foo.js" type="text/javascript"></script></head><body></body></html>'
29
+ url = Url.new('http://localhost:3000/foo')
30
+ connection.setResponse(url, content, 'text/html')
31
+
32
+ content = 'document.title = "FOO";'
33
+ url = Url.new('http://localhost:3000/javascripts/foo.js')
34
+ connection.setResponse(url, content, 'application/javascript')
35
+
36
+ client = WebClient.new
37
+ client.setCssEnabled(true)
38
+ client.setJavaScriptEnabled(true)
39
+ client.setWebConnection(Rjb::bind(connection, 'com.gargoylesoftware.htmlunit.WebConnection'))
40
+ # client.setWebConnection(connection)
41
+ page = client.getPage('http://localhost:3000/foo')
42
+ # puts page.asXml
@@ -0,0 +1,129 @@
1
+ # running this script, e.g. with
2
+ #
3
+ # ruby test/playground/stack_level_problem.rb
4
+ #
5
+ # will yield an error message like this:
6
+ #
7
+ # stack level too deep
8
+ # test/playground/stack_level_problem.rb:94:in `getResponse'
9
+ # test/playground/stack_level_problem.rb:109:in `method_missing'
10
+ # test/playground/stack_level_problem.rb:109
11
+ #
12
+ # The fun part is that whenever I change a single line, e.g. output
13
+ # something with puts, I'll get the same error from a different place.
14
+ #
15
+ # Also, there doesn't seem to happen any "real" recursion. Maybe Ruby
16
+ # just "thinks" there's recursion happening. Or maybe something
17
+ # completely unrelated is happening?
18
+
19
+ $: << File.expand_path(File.dirname(__FILE__) + "/../../lib")
20
+ require 'steam'
21
+ require 'steam/browser/html_unit/client'
22
+ include Steam
23
+
24
+ class WebResponse
25
+ Java.import 'java.net.Url'
26
+ Java.import 'java.io.ByteArrayInputStream'
27
+ Java.import 'com.gargoylesoftware.htmlunit.WebRequestSettings'
28
+
29
+ attr_reader :request, :response
30
+
31
+ def initialize(request, response)
32
+ @request = request
33
+ @response = response
34
+ end
35
+
36
+ def getRequestSettings
37
+ Java::WebRequestSettings.new(Java::Url.new('http://localhost:3000/'))
38
+ end
39
+
40
+ def getResponseHeaders
41
+ Java::Arrays.asList([])
42
+ end
43
+
44
+ def getResponseHeaderValue(name)
45
+ ''
46
+ end
47
+
48
+ def getStatusCode
49
+ 200
50
+ end
51
+
52
+ def getStatusMessage
53
+ 'OK'
54
+ end
55
+
56
+ def getContentType
57
+ response.content_type.split(';').first
58
+ end
59
+
60
+ def getContentCharset
61
+ 'utf-8'
62
+ end
63
+
64
+ def getContentCharsetOrNull
65
+ 'utf-8'
66
+ end
67
+
68
+ def getContentAsString
69
+ @body ||= response.body.join
70
+ end
71
+
72
+ def getContentAsStream
73
+ bytes = getContentAsString.unpack('C*')
74
+ Java::ByteArrayInputStream.new_with_sig('[B', bytes)
75
+ end
76
+ end
77
+
78
+ class Connection
79
+ page = <<-erb
80
+ <html>
81
+ <head>
82
+ <script>
83
+ document.title = 'pre ajax call';
84
+ function some_ajax(url) {
85
+ http = new XMLHttpRequest();
86
+ http.open("GET", url, true);
87
+ http.onreadystatechange = function() {
88
+ document.title = document.title + ' ' + http.readyState
89
+ if(http.readyState == 4) document.title = http.responseText
90
+ }
91
+ http.send(null);
92
+ }
93
+ some_ajax('/ajax/1');
94
+ // some_ajax('/ajax/2');
95
+ </script>
96
+ </head>
97
+ </html>
98
+ erb
99
+
100
+ @@responses = {
101
+ 'http://localhost:3000/' => Rack::Response.new(page, 200),
102
+ 'http://localhost:3000/ajax/1' => Rack::Response.new('post ajax call!', 200, 'Content-Type' => 'application/javascript')
103
+ }
104
+
105
+ @@track = []
106
+
107
+ def getResponse(request)
108
+ url = request.getUrl.toString.dup
109
+ method = request.getHttpMethod.toString.dup
110
+ request = Request.new(method, url) # headers
111
+ response = @@responses[url]
112
+ Rjb::bind(WebResponse.new(request, response), 'com.gargoylesoftware.htmlunit.WebResponse')
113
+ rescue Exception => e
114
+ puts e.message
115
+ e.backtrace.each { |line| puts line }
116
+ end
117
+ end
118
+
119
+
120
+ client = Java::WebClient.new(Java::BrowserVersion.FIREFOX_3)
121
+ client.setCssEnabled(true)
122
+ client.setJavaScriptEnabled(true)
123
+
124
+ connection = Connection.new
125
+ client.setWebConnection(Rjb::bind(connection, 'com.gargoylesoftware.htmlunit.WebConnection'))
126
+
127
+ page = client.getPage('http://localhost:3000/')
128
+ # puts page.asXml
129
+ # puts page.getTitleText