tarantula 0.0.5
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/CHANGELOG +2 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +106 -0
- data/Rakefile +80 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/laf/images/background.jpg +0 -0
- data/laf/images/relevance-os-logo.gif +0 -0
- data/laf/images/tab.png +0 -0
- data/laf/images/table-sort.gif +0 -0
- data/laf/images/tarantula-sprites.png +0 -0
- data/laf/javascripts/jquery-1.2.3.js +3408 -0
- data/laf/javascripts/jquery-ui-tabs.js +890 -0
- data/laf/javascripts/jquery.tablesorter.js +861 -0
- data/laf/javascripts/tarantula.js +10 -0
- data/laf/stylesheets/tarantula.css +638 -0
- data/laf/stylesheets/ui.tabs.css +113 -0
- data/lib/relevance/core_extensions/ellipsize.rb +34 -0
- data/lib/relevance/core_extensions/file.rb +9 -0
- data/lib/relevance/core_extensions/response.rb +9 -0
- data/lib/relevance/core_extensions/test_case.rb +12 -0
- data/lib/relevance/tarantula.rb +63 -0
- data/lib/relevance/tarantula/attack.rb +15 -0
- data/lib/relevance/tarantula/attack_form_submission.rb +75 -0
- data/lib/relevance/tarantula/attack_handler.rb +37 -0
- data/lib/relevance/tarantula/crawler.rb +240 -0
- data/lib/relevance/tarantula/detail.html.erb +77 -0
- data/lib/relevance/tarantula/form.rb +21 -0
- data/lib/relevance/tarantula/form_submission.rb +70 -0
- data/lib/relevance/tarantula/html_document_handler.rb +36 -0
- data/lib/relevance/tarantula/html_report_helper.rb +56 -0
- data/lib/relevance/tarantula/html_reporter.rb +105 -0
- data/lib/relevance/tarantula/index.html.erb +48 -0
- data/lib/relevance/tarantula/invalid_html_handler.rb +18 -0
- data/lib/relevance/tarantula/io_reporter.rb +34 -0
- data/lib/relevance/tarantula/link.rb +56 -0
- data/lib/relevance/tarantula/log_grabber.rb +16 -0
- data/lib/relevance/tarantula/rails_integration_proxy.rb +70 -0
- data/lib/relevance/tarantula/recording.rb +12 -0
- data/lib/relevance/tarantula/response.rb +13 -0
- data/lib/relevance/tarantula/result.rb +66 -0
- data/lib/relevance/tarantula/test_report.html.erb +34 -0
- data/lib/relevance/tarantula/tidy_handler.rb +32 -0
- data/lib/relevance/tarantula/transform.rb +17 -0
- data/manifest.txt +117 -0
- data/rails/init.rb +1 -0
- data/tarantula.gemspec +48 -0
- data/tasks/tarantula_tasks.rake +34 -0
- data/template/tarantula_test.rb +12 -0
- data/test/relevance/core_extensions/ellipsize_test.rb +19 -0
- data/test/relevance/core_extensions/file_test.rb +8 -0
- data/test/relevance/core_extensions/response_test.rb +29 -0
- data/test/relevance/core_extensions/test_case_test.rb +16 -0
- data/test/relevance/tarantula/attack_form_submission_test.rb +79 -0
- data/test/relevance/tarantula/attack_handler_test.rb +29 -0
- data/test/relevance/tarantula/crawler_test.rb +296 -0
- data/test/relevance/tarantula/form_submission_test.rb +71 -0
- data/test/relevance/tarantula/form_test.rb +50 -0
- data/test/relevance/tarantula/html_document_handler_test.rb +43 -0
- data/test/relevance/tarantula/html_report_helper_test.rb +47 -0
- data/test/relevance/tarantula/html_reporter_test.rb +82 -0
- data/test/relevance/tarantula/invalid_html_handler_test.rb +33 -0
- data/test/relevance/tarantula/io_reporter_test.rb +11 -0
- data/test/relevance/tarantula/link_test.rb +61 -0
- data/test/relevance/tarantula/log_grabber_test.rb +26 -0
- data/test/relevance/tarantula/rails_integration_proxy_test.rb +94 -0
- data/test/relevance/tarantula/result_test.rb +85 -0
- data/test/relevance/tarantula/tidy_handler_test.rb +58 -0
- data/test/relevance/tarantula/transform_test.rb +21 -0
- data/test/relevance/tarantula_test.rb +23 -0
- data/test/test_helper.rb +34 -0
- data/tmp/test_output/images/background.jpg +0 -0
- data/tmp/test_output/images/relevance-os-logo.gif +0 -0
- data/tmp/test_output/images/tab.png +0 -0
- data/tmp/test_output/images/table-sort.gif +0 -0
- data/tmp/test_output/images/tarantula-sprites.png +0 -0
- data/tmp/test_output/index.html +255 -0
- data/tmp/test_output/javascripts/jquery-1.2.3.js +3408 -0
- data/tmp/test_output/javascripts/jquery-ui-tabs.js +890 -0
- data/tmp/test_output/javascripts/jquery.tablesorter.js +861 -0
- data/tmp/test_output/javascripts/tarantula.js +10 -0
- data/tmp/test_output/stylesheets/tarantula.css +638 -0
- data/tmp/test_output/stylesheets/ui.tabs.css +113 -0
- data/tmp/test_output/test_user_pages/1.html +71 -0
- data/tmp/test_output/test_user_pages/10.html +71 -0
- data/tmp/test_output/test_user_pages/11.html +71 -0
- data/tmp/test_output/test_user_pages/12.html +71 -0
- data/tmp/test_output/test_user_pages/13.html +71 -0
- data/tmp/test_output/test_user_pages/14.html +71 -0
- data/tmp/test_output/test_user_pages/15.html +71 -0
- data/tmp/test_output/test_user_pages/16.html +71 -0
- data/tmp/test_output/test_user_pages/17.html +71 -0
- data/tmp/test_output/test_user_pages/18.html +71 -0
- data/tmp/test_output/test_user_pages/19.html +71 -0
- data/tmp/test_output/test_user_pages/2.html +71 -0
- data/tmp/test_output/test_user_pages/20.html +71 -0
- data/tmp/test_output/test_user_pages/3.html +71 -0
- data/tmp/test_output/test_user_pages/4.html +71 -0
- data/tmp/test_output/test_user_pages/5.html +71 -0
- data/tmp/test_output/test_user_pages/6.html +71 -0
- data/tmp/test_output/test_user_pages/7.html +71 -0
- data/tmp/test_output/test_user_pages/8.html +71 -0
- data/tmp/test_output/test_user_pages/9.html +71 -0
- data/uninstall.rb +1 -0
- data/vendor/xss-shield/MIT-LICENSE +20 -0
- data/vendor/xss-shield/README +76 -0
- data/vendor/xss-shield/init.rb +16 -0
- data/vendor/xss-shield/lib/xss_shield.rb +6 -0
- data/vendor/xss-shield/lib/xss_shield/erb_hacks.rb +111 -0
- data/vendor/xss-shield/lib/xss_shield/haml_hacks.rb +42 -0
- data/vendor/xss-shield/lib/xss_shield/safe_string.rb +47 -0
- data/vendor/xss-shield/lib/xss_shield/secure_helpers.rb +40 -0
- data/vendor/xss-shield/test/test_actionview_integration.rb +40 -0
- data/vendor/xss-shield/test/test_erb.rb +44 -0
- data/vendor/xss-shield/test/test_haml.rb +43 -0
- data/vendor/xss-shield/test/test_helpers.rb +25 -0
- data/vendor/xss-shield/test/test_safe_string.rb +55 -0
- metadata +283 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
3
|
+
|
|
4
|
+
<html>
|
|
5
|
+
<head>
|
|
6
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
|
7
|
+
<title>Tarantula report detail <%= short_description %></title>
|
|
8
|
+
<script type="text/javascript" src="../javascripts/jquery-1.2.3.js"></script>
|
|
9
|
+
<script type="text/javascript" src="../javascripts/jquery.tablesorter.js"></script>
|
|
10
|
+
<script type="text/javascript" src="../javascripts/jquery-ui-tabs.js"></script>
|
|
11
|
+
<script type="text/javascript" src="../javascripts/tarantula.js"></script>
|
|
12
|
+
<link type="text/css" media="screen" rel="stylesheet" href="../stylesheets/tarantula.css"/>
|
|
13
|
+
<link type="text/css" media="screen" rel="stylesheet" href="../stylesheets/ui.tabs.css"/>
|
|
14
|
+
|
|
15
|
+
<!--[if lte IE 7]>
|
|
16
|
+
<link rel="stylesheet" href="jqeury.tabs-ie.css" type="text/css" media="projection, screen" />
|
|
17
|
+
<![endif]-->
|
|
18
|
+
|
|
19
|
+
</head>
|
|
20
|
+
|
|
21
|
+
<body id="top">
|
|
22
|
+
|
|
23
|
+
<div id="container">
|
|
24
|
+
|
|
25
|
+
<div id="header">
|
|
26
|
+
<hr class="top"/>
|
|
27
|
+
<h1><span>Tarantula : Eight Legs, Two Fangs, and an Attitude</span></h1>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div id="page-container">
|
|
31
|
+
<hr class="top"/>
|
|
32
|
+
<div id="page">
|
|
33
|
+
<h1>Tarantula report detail <%= short_description %></h1>
|
|
34
|
+
<p>Generated on <%= Time.now %> (<a href="../index.html">Back</a>)</p>
|
|
35
|
+
<p>Visit <a href="<%= full_url %>"><%= full_url %></a></p>
|
|
36
|
+
<p>Response: <%= code %></p>
|
|
37
|
+
<p>Referrer: <%= referrer || "" %></p>
|
|
38
|
+
<div id="tabs-container">
|
|
39
|
+
<ul>
|
|
40
|
+
<li><a href="#fragment-1"><span>Data</span></a></li>
|
|
41
|
+
<li><a href="#fragment-2"><span>Body</span></a></li>
|
|
42
|
+
<li><a href="#fragment-3"><span>Log</span></a></li>
|
|
43
|
+
</ul>
|
|
44
|
+
<div id="fragment-1">
|
|
45
|
+
<% if data %>
|
|
46
|
+
<%= wrap_in_line_number_table(data) %>
|
|
47
|
+
<% else %>
|
|
48
|
+
<p>No Data</p>
|
|
49
|
+
<% end %>
|
|
50
|
+
</div>
|
|
51
|
+
<div id="fragment-2">
|
|
52
|
+
<% if body %>
|
|
53
|
+
<%= wrap_in_line_number_table(body) %>
|
|
54
|
+
<% else %>
|
|
55
|
+
<p>No Body</p>
|
|
56
|
+
<% end %>
|
|
57
|
+
</div>
|
|
58
|
+
<div id="fragment-3">
|
|
59
|
+
<% if log %>
|
|
60
|
+
<%= wrap_in_line_number_table(log) {|line| wrap_stack_trace_line(line)} %>
|
|
61
|
+
<% else %>
|
|
62
|
+
<p>No Log</p>
|
|
63
|
+
<% end %>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
<div id="sidebar">
|
|
69
|
+
<h3><span>Tarantula</span></h3>
|
|
70
|
+
<p>Tarantula is an open-source tool for testing Rails web applications. Tarantula is developed by <a href="http://thinkrelevance.com">Relevance, Inc.</a> and lives at <a href="http://opensource.thinkrelevance.com">http://opensource.thinkrelevance.com</a>.</p>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</body>
|
|
74
|
+
|
|
75
|
+
</html>
|
|
76
|
+
|
|
77
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class Relevance::Tarantula::Form
|
|
2
|
+
extend Forwardable
|
|
3
|
+
def_delegators("@tag", :search)
|
|
4
|
+
|
|
5
|
+
def initialize(tag)
|
|
6
|
+
@tag = tag
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def action
|
|
10
|
+
@tag['action'].downcase
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def method
|
|
14
|
+
(rails_method_hack or @tag['method'] or 'get').downcase
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def rails_method_hack
|
|
18
|
+
(tag = @tag.at('input[@name="_method"]')) && tag["value"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
class Relevance::Tarantula::FormSubmission
|
|
2
|
+
attr_accessor :method, :action, :data
|
|
3
|
+
def initialize(form)
|
|
4
|
+
@method = form.method
|
|
5
|
+
@action = form.action
|
|
6
|
+
@data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.mutate(form)
|
|
10
|
+
[self.new(form)]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
"#{action} #{method} #{data.inspect}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# a form's signature is what makes it unique (e.g. action + fields)
|
|
18
|
+
# used to keep track of which forms we have submitted already
|
|
19
|
+
def signature
|
|
20
|
+
[action, data.keys.sort]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create_random_data_for(form, tag_selector)
|
|
24
|
+
form.search(tag_selector).inject({}) do |form_args, input|
|
|
25
|
+
# TODO: test
|
|
26
|
+
form_args[input['name']] = random_data(input) if input['name']
|
|
27
|
+
form_args
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def mutate_inputs(form)
|
|
32
|
+
create_random_data_for(form, 'input')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def mutate_text_areas(form)
|
|
36
|
+
create_random_data_for(form, 'textarea')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def mutate_selects(form)
|
|
40
|
+
form.search('select').inject({}) do |form_args, select|
|
|
41
|
+
options = select.search('option')
|
|
42
|
+
option = options.rand
|
|
43
|
+
form_args[select['name']] = option['value']
|
|
44
|
+
form_args
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def random_data(input)
|
|
49
|
+
case input['name']
|
|
50
|
+
when /amount/ : random_int
|
|
51
|
+
when /_id$/ : random_whole_number
|
|
52
|
+
when /uploaded_data/ : nil
|
|
53
|
+
when /^_method$/ : input['value']
|
|
54
|
+
when nil : input['value']
|
|
55
|
+
else random_int
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def big_number
|
|
60
|
+
10000 # arbitrary
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def random_int
|
|
64
|
+
rand(big_number) - (big_number/2)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def random_whole_number
|
|
68
|
+
rand(big_number)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'hpricot'
|
|
2
|
+
|
|
3
|
+
class Relevance::Tarantula::HtmlDocumentHandler
|
|
4
|
+
extend Forwardable
|
|
5
|
+
def_delegators("@crawler", :queue_link, :queue_form)
|
|
6
|
+
|
|
7
|
+
def initialize(crawler)
|
|
8
|
+
@crawler = crawler
|
|
9
|
+
end
|
|
10
|
+
# HTML::Document shouts to stderr when it sees ugly HTML
|
|
11
|
+
# We don't want this -- the InvalidHtmlHandler will deal with it
|
|
12
|
+
def html_doc_without_stderr_noise(html)
|
|
13
|
+
body = nil
|
|
14
|
+
Recording.stderr do
|
|
15
|
+
body = Hpricot html
|
|
16
|
+
end
|
|
17
|
+
body
|
|
18
|
+
end
|
|
19
|
+
def handle(result)
|
|
20
|
+
response = result.response
|
|
21
|
+
url = result.url
|
|
22
|
+
return unless response.html?
|
|
23
|
+
body = html_doc_without_stderr_noise(response.body)
|
|
24
|
+
body.search('a').each do |tag|
|
|
25
|
+
queue_link(tag, url)
|
|
26
|
+
end
|
|
27
|
+
body.search('link').each do |tag|
|
|
28
|
+
queue_link(tag, url)
|
|
29
|
+
end
|
|
30
|
+
body.search('form').each do |form|
|
|
31
|
+
form['action'] = url unless form['action']
|
|
32
|
+
queue_form(form, url)
|
|
33
|
+
end
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require "erb"
|
|
2
|
+
module Relevance::Tarantula::HtmlReportHelper
|
|
3
|
+
include ERB::Util
|
|
4
|
+
include Relevance::Tarantula
|
|
5
|
+
def wrap_in_line_number_table(text, &blk)
|
|
6
|
+
x = Builder::XmlMarkup.new
|
|
7
|
+
x.table(:class => "grid tablesorter") do
|
|
8
|
+
x.thead do
|
|
9
|
+
x.tr do
|
|
10
|
+
x.th(:class => "sort asc") do
|
|
11
|
+
x.span("Line \#")
|
|
12
|
+
x.span(:class => "sort") do
|
|
13
|
+
x.em do
|
|
14
|
+
x << '↥'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
x.th(:class => "sort left") do
|
|
19
|
+
x.span("Line")
|
|
20
|
+
x.span(:class => "sort") do
|
|
21
|
+
x.em do
|
|
22
|
+
x << '↥'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
text.split("\n").each_with_index do |line, index|
|
|
29
|
+
x.tr do
|
|
30
|
+
x.td(index+1)
|
|
31
|
+
if block_given?
|
|
32
|
+
x.td {x << yield(line)}
|
|
33
|
+
else
|
|
34
|
+
x.td(line)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
x.target!
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def textmate_url(file, line_no)
|
|
43
|
+
"txmt://open?url=file://#{File.expand_path(File.join(rails_root,file))}&line_no=#{line_no}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def wrap_stack_trace_line(text)
|
|
47
|
+
if text =~ %r{^\s*(/[^:]+):(\d+):([^:]+)$}
|
|
48
|
+
file = h($1) # .to_s_xss_protected
|
|
49
|
+
line_number = $2
|
|
50
|
+
message = h($3) # .to_s_xss_protected
|
|
51
|
+
"<a href='#{textmate_url(file, line_number)}'>#{file}:#{line_number}</a>:#{message}" # .mark_as_xss_protected
|
|
52
|
+
else
|
|
53
|
+
h(text) # .to_s_xss_protected
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
class Relevance::Tarantula::HtmlReporter
|
|
2
|
+
|
|
3
|
+
include Relevance::Tarantula
|
|
4
|
+
attr_accessor :basedir, :results
|
|
5
|
+
delegate :successes, :failures, :to => :results
|
|
6
|
+
|
|
7
|
+
HtmlResultOverview = Struct.new(:code, :url, :description, :method, :referrer, :file_name)
|
|
8
|
+
|
|
9
|
+
def initialize(basedir)
|
|
10
|
+
@basedir = basedir
|
|
11
|
+
@results = Struct.new(:successes, :failures).new([], [])
|
|
12
|
+
FileUtils.mkdir_p(@basedir)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def report(result)
|
|
16
|
+
return if result.nil?
|
|
17
|
+
|
|
18
|
+
create_detail_report(result)
|
|
19
|
+
|
|
20
|
+
collection = result.success ? results.successes : results.failures
|
|
21
|
+
collection << HtmlResultOverview.new(
|
|
22
|
+
result.code, result.url, result.description, result.method, result.referrer, result.file_name
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def finish_report(test_name)
|
|
27
|
+
puts "Writing results to #{basedir}"
|
|
28
|
+
copy_styles unless styles_exist?
|
|
29
|
+
create_index unless index_exists?
|
|
30
|
+
update_index(test_name)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def create_detail_report(result)
|
|
34
|
+
template = ERB.new(template("detail.html.erb"))
|
|
35
|
+
output(result.file_name, template.result(result.send(:binding)), result.test_name)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def copy_styles
|
|
39
|
+
# not using cp_r because it picks up .svn crap
|
|
40
|
+
FileUtils.mkdir_p(File.join(basedir, "stylesheets"))
|
|
41
|
+
Dir.glob("#{tarantula_home}/laf/stylesheets/*.css").each do |file|
|
|
42
|
+
FileUtils.cp(file, File.join(basedir, "stylesheets"))
|
|
43
|
+
end
|
|
44
|
+
FileUtils.mkdir_p(File.join(basedir, "images"))
|
|
45
|
+
Dir.glob("#{tarantula_home}/laf/images/*.{jpg,gif,png}").each do |file|
|
|
46
|
+
FileUtils.cp(file, File.join(basedir, "images"))
|
|
47
|
+
end
|
|
48
|
+
FileUtils.mkdir_p(File.join(basedir, "javascripts"))
|
|
49
|
+
Dir.glob("#{tarantula_home}/laf/javascripts/*.js").each do |file|
|
|
50
|
+
FileUtils.cp(file, File.join(basedir, "javascripts"))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_index
|
|
55
|
+
template = ERB.new(template("index.html.erb"))
|
|
56
|
+
output("index.html", template.result(binding))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def update_index(test_name)
|
|
60
|
+
File.open(File.join(basedir, "index.html"), "r+") do |file|
|
|
61
|
+
doc = Hpricot file.read
|
|
62
|
+
tabs_container = doc.search "#tabs-container ul"
|
|
63
|
+
results_container = doc.search "#tabs-container"
|
|
64
|
+
tabs_container.append tab_html(test_name)
|
|
65
|
+
results_container.append results_html(test_name)
|
|
66
|
+
file.rewind
|
|
67
|
+
file.write doc.to_s
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def index_exists?
|
|
72
|
+
File.exists?(File.join(basedir, "index.html"))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def styles_exist?
|
|
76
|
+
File.exists?(File.join(basedir, "stylesheets", "tarantula.css"))
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def tab_html(test_name)
|
|
80
|
+
"<li><a href='##{test_name}'><span>#{test_name}</span></a></li>"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def results_html(test_name)
|
|
84
|
+
template = ERB.new(template("test_report.html.erb"))
|
|
85
|
+
template.result(binding)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def template(name)
|
|
89
|
+
File.read(File.join(File.dirname(__FILE__), name))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def output(name, body, subdir = '')
|
|
93
|
+
FileUtils.mkdir_p(File.join(basedir, subdir)) unless subdir.empty?
|
|
94
|
+
File.open(File.join(basedir, subdir, name), "w") do |file|
|
|
95
|
+
file.write body
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# CSS class for HTML status codes
|
|
100
|
+
def class_for_code(code)
|
|
101
|
+
"r#{Integer(code)/100}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
3
|
+
|
|
4
|
+
<html>
|
|
5
|
+
<head>
|
|
6
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
|
7
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
8
|
+
<meta name="Author" content="Erik Yowell; erik[at]thinkrelevance.com"/>
|
|
9
|
+
<title>Tarantula report</title>
|
|
10
|
+
<script type="text/javascript" src="javascripts/jquery-1.2.3.js"></script>
|
|
11
|
+
<script type="text/javascript" src="javascripts/jquery.tablesorter.js"></script>
|
|
12
|
+
<script type="text/javascript" src="javascripts/jquery-ui-tabs.js"></script>
|
|
13
|
+
<script type="text/javascript" src="javascripts/tarantula.js"></script>
|
|
14
|
+
<link type="text/css" media="screen" rel="stylesheet" href="stylesheets/tarantula.css"/>
|
|
15
|
+
<link type="text/css" media="screen" rel="stylesheet" href="stylesheets/ui.tabs.css"/>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body id="top">
|
|
19
|
+
|
|
20
|
+
<div id="container">
|
|
21
|
+
|
|
22
|
+
<div id="header">
|
|
23
|
+
<hr class="top"/>
|
|
24
|
+
<h1><span>Tarantula : Eight Legs, Two Fangs, and an Attitude</span></h1>
|
|
25
|
+
<ul class="navigation">
|
|
26
|
+
<li><a href="#" class="result-all"><span>All</span> <em><%= successes.size + failures.size %></em></a></li>
|
|
27
|
+
<li><a href="#" class="result-failure"><span>Failures</span> <em><%= failures.size %></em></a></li>
|
|
28
|
+
<li><a href="#" class="result-success"><span>Successful</span> <em><%= successes.size %></em></a></li>
|
|
29
|
+
</ul>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div id="page-container">
|
|
33
|
+
<hr class="top"/>
|
|
34
|
+
<div id="page">
|
|
35
|
+
<p>Generated on <%= Time.now %></p>
|
|
36
|
+
<div id="tabs-container">
|
|
37
|
+
<ul>
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<div id="sidebar">
|
|
42
|
+
<h3><span>Tarantula</span></h3>
|
|
43
|
+
<p>Tarantula is an open-source tool for testing Rails web applications. Tarantula is developed by <a href="http://thinkrelevance.com">Relevance, Inc.</a> and lives at <a href="http://opensource.thinkrelevance.com">http://opensource.thinkrelevance.com</a>.</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</body>
|
|
47
|
+
|
|
48
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class Relevance::Tarantula::InvalidHtmlHandler
|
|
2
|
+
include Relevance::Tarantula
|
|
3
|
+
def handle(result)
|
|
4
|
+
response = result.response
|
|
5
|
+
return unless response.html?
|
|
6
|
+
begin
|
|
7
|
+
body = HTML::Document.new(response.body, true)
|
|
8
|
+
rescue Exception => e
|
|
9
|
+
error_result = result.dup
|
|
10
|
+
error_result.success = false
|
|
11
|
+
error_result.description = "Bad HTML (Scanner)"
|
|
12
|
+
error_result.data = e.message
|
|
13
|
+
error_result
|
|
14
|
+
else
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class Relevance::Tarantula::IOReporter
|
|
2
|
+
|
|
3
|
+
include Relevance::Tarantula
|
|
4
|
+
attr_accessor :io, :results
|
|
5
|
+
delegate :successes, :failures, :to => :results
|
|
6
|
+
|
|
7
|
+
IOResultOverview = Struct.new(:code, :url)
|
|
8
|
+
|
|
9
|
+
def initialize(io)
|
|
10
|
+
@io = io
|
|
11
|
+
@results = Struct.new(:successes, :failures).new([], [])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def report(result)
|
|
15
|
+
return if result.nil?
|
|
16
|
+
|
|
17
|
+
unless result.success # collection = result.success ? results.successes : results.failures
|
|
18
|
+
results.failures << IOResultOverview.new(
|
|
19
|
+
result.code, result.url
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def finish_report(test_name)
|
|
25
|
+
unless (failures).empty?
|
|
26
|
+
io.puts "****** FAILURES"
|
|
27
|
+
failures.each do |failure|
|
|
28
|
+
io.puts "#{failure.code}: #{failure.url}"
|
|
29
|
+
end
|
|
30
|
+
raise "#{failures.size} failures"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|