panmind-tarantula 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/CHANGELOG +49 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +171 -0
  4. data/Rakefile +83 -0
  5. data/VERSION.yml +4 -0
  6. data/examples/example_helper.rb +57 -0
  7. data/examples/relevance/core_extensions/ellipsize_example.rb +19 -0
  8. data/examples/relevance/core_extensions/file_example.rb +8 -0
  9. data/examples/relevance/core_extensions/response_example.rb +29 -0
  10. data/examples/relevance/core_extensions/test_case_example.rb +20 -0
  11. data/examples/relevance/tarantula/attack_handler_example.rb +29 -0
  12. data/examples/relevance/tarantula/basic_attack_example.rb +12 -0
  13. data/examples/relevance/tarantula/crawler_example.rb +375 -0
  14. data/examples/relevance/tarantula/form_example.rb +50 -0
  15. data/examples/relevance/tarantula/form_submission_example.rb +171 -0
  16. data/examples/relevance/tarantula/html_document_handler_example.rb +43 -0
  17. data/examples/relevance/tarantula/html_report_helper_example.rb +46 -0
  18. data/examples/relevance/tarantula/html_reporter_example.rb +82 -0
  19. data/examples/relevance/tarantula/invalid_html_handler_example.rb +33 -0
  20. data/examples/relevance/tarantula/io_reporter_example.rb +11 -0
  21. data/examples/relevance/tarantula/link_example.rb +84 -0
  22. data/examples/relevance/tarantula/log_grabber_example.rb +26 -0
  23. data/examples/relevance/tarantula/rails_integration_proxy_example.rb +101 -0
  24. data/examples/relevance/tarantula/result_example.rb +85 -0
  25. data/examples/relevance/tarantula/tidy_handler_example.rb +58 -0
  26. data/examples/relevance/tarantula/transform_example.rb +20 -0
  27. data/examples/relevance/tarantula_example.rb +23 -0
  28. data/laf/images/header_bg.jpg +0 -0
  29. data/laf/images/logo.png +0 -0
  30. data/laf/images/tagline.png +0 -0
  31. data/laf/javascripts/jquery-1.2.3.js +3408 -0
  32. data/laf/javascripts/jquery-ui-tabs.js +890 -0
  33. data/laf/javascripts/jquery.tablesorter.js +861 -0
  34. data/laf/javascripts/tarantula.js +10 -0
  35. data/laf/stylesheets/tarantula.css +346 -0
  36. data/lib/relevance/core_extensions/ellipsize.rb +34 -0
  37. data/lib/relevance/core_extensions/file.rb +9 -0
  38. data/lib/relevance/core_extensions/metaclass.rb +78 -0
  39. data/lib/relevance/core_extensions/response.rb +9 -0
  40. data/lib/relevance/core_extensions/string_chars_fix.rb +11 -0
  41. data/lib/relevance/core_extensions/test_case.rb +19 -0
  42. data/lib/relevance/tarantula.rb +59 -0
  43. data/lib/relevance/tarantula/attack.rb +18 -0
  44. data/lib/relevance/tarantula/attack_handler.rb +37 -0
  45. data/lib/relevance/tarantula/basic_attack.rb +40 -0
  46. data/lib/relevance/tarantula/crawler.rb +254 -0
  47. data/lib/relevance/tarantula/detail.html.erb +81 -0
  48. data/lib/relevance/tarantula/form.rb +23 -0
  49. data/lib/relevance/tarantula/form_submission.rb +88 -0
  50. data/lib/relevance/tarantula/html_document_handler.rb +36 -0
  51. data/lib/relevance/tarantula/html_report_helper.rb +39 -0
  52. data/lib/relevance/tarantula/html_reporter.rb +105 -0
  53. data/lib/relevance/tarantula/index.html.erb +37 -0
  54. data/lib/relevance/tarantula/invalid_html_handler.rb +18 -0
  55. data/lib/relevance/tarantula/io_reporter.rb +34 -0
  56. data/lib/relevance/tarantula/link.rb +76 -0
  57. data/lib/relevance/tarantula/log_grabber.rb +16 -0
  58. data/lib/relevance/tarantula/rails_integration_proxy.rb +87 -0
  59. data/lib/relevance/tarantula/recording.rb +12 -0
  60. data/lib/relevance/tarantula/response.rb +13 -0
  61. data/lib/relevance/tarantula/result.rb +77 -0
  62. data/lib/relevance/tarantula/test_report.html.erb +32 -0
  63. data/lib/relevance/tarantula/tidy_handler.rb +32 -0
  64. data/lib/relevance/tarantula/transform.rb +17 -0
  65. data/tasks/tarantula_tasks.rake +42 -0
  66. data/template/tarantula_test.rb +22 -0
  67. metadata +213 -0
@@ -0,0 +1,76 @@
1
+ class Relevance::Tarantula::Link
2
+ include Relevance::Tarantula
3
+
4
+ class << self
5
+ include ActionView::Helpers::UrlHelper
6
+ # method_javascript_function needs this method
7
+ def protect_against_forgery?
8
+ false
9
+ end
10
+ end
11
+
12
+ METHOD_REGEXPS = {}
13
+ [:put, :delete, :post].each do |m|
14
+ # remove submit from the end so we'll match with or without forgery protection
15
+ s = method_javascript_function(m).gsub( /f.submit();/, "" )
16
+ # don't just match this.href in case a different url was passed originally
17
+ s = Regexp.escape(s).gsub( /this.href/, ".*" )
18
+ METHOD_REGEXPS[m] = /#{s}/
19
+ end
20
+
21
+ attr_accessor :href, :crawler, :referrer
22
+
23
+ def initialize(link, crawler, referrer)
24
+ @crawler, @referrer = crawler, referrer
25
+
26
+ if String === link || link.nil?
27
+ @href = transform_url(link)
28
+ @method = :get
29
+ else # should be a tag
30
+ @href = link['href'] ? transform_url(link['href'].downcase) : nil
31
+ @tag = link
32
+ end
33
+ end
34
+
35
+ def crawl
36
+ response = crawler.follow(method, href)
37
+ log "Response #{response.code} for #{self}"
38
+ crawler.handle_link_results(self, make_result(response))
39
+ end
40
+
41
+ def make_result(response)
42
+ crawler.make_result(:method => method,
43
+ :url => href,
44
+ :response => response,
45
+ :referrer => referrer)
46
+ end
47
+
48
+ def method
49
+ @method ||= begin
50
+ (@tag &&
51
+ [:put, :delete, :post].detect do |m| # post should be last since it's least specific
52
+ @tag['onclick'] =~ METHOD_REGEXPS[m]
53
+ end) ||
54
+ :get
55
+ end
56
+ end
57
+
58
+ def transform_url(link)
59
+ crawler.transform_url(link)
60
+ end
61
+
62
+ def ==(obj)
63
+ obj.respond_to?(:href) && obj.respond_to?(:method) &&
64
+ self.href.to_s == obj.href.to_s && self.method.to_s == obj.method.to_s
65
+ end
66
+ alias :eql? :==
67
+
68
+ def hash
69
+ to_s.hash
70
+ end
71
+
72
+ def to_s
73
+ "<Relevance::Tarantula::Link href=#{href}, method=#{method}>"
74
+ end
75
+
76
+ end
@@ -0,0 +1,16 @@
1
+ class Relevance::Tarantula::LogGrabber
2
+ attr_accessor :path
3
+ def initialize(path)
4
+ @path = path
5
+ end
6
+
7
+ def clear!
8
+ File.open(@path, "w")
9
+ end
10
+
11
+ def grab!
12
+ File.read(@path)
13
+ ensure
14
+ clear!
15
+ end
16
+ end
@@ -0,0 +1,87 @@
1
+ require 'test/unit'
2
+
3
+ class Relevance::Tarantula::RailsIntegrationProxy
4
+ include Relevance::Tarantula
5
+ extend Relevance::Tarantula
6
+ extend Forwardable
7
+ attr_accessor :integration_test
8
+
9
+ def self.rails_integration_test(integration_test, options = {})
10
+ t = Crawler.new
11
+ t.max_url_length = options[:max_url_length] if options[:max_url_length]
12
+ t.proxy = RailsIntegrationProxy.new(integration_test)
13
+ t.handlers << HtmlDocumentHandler.new(t)
14
+ t.handlers << InvalidHtmlHandler.new
15
+ t.log_grabber = Relevance::Tarantula::LogGrabber.new(File.join(rails_root, "log/test.log"))
16
+ t.skip_uri_patterns << /logout$/
17
+ t.skip_uri_patterns.delete /^http/
18
+ t.skip_uri_patterns.push /^https?:\/\/(?!#{integration_test.host})/
19
+
20
+ t.transform_url_patterns += [
21
+ [/\?\d+$/, ''], # strip trailing numbers for assets
22
+ [/^https?:\/\/#{integration_test.host}/, ''] # strip full path down to relative
23
+ ]
24
+ t.test_name = t.proxy.integration_test.method_name
25
+ t.reporters << Relevance::Tarantula::HtmlReporter.new(t.report_dir)
26
+ t
27
+ end
28
+
29
+ def initialize(integration_test)
30
+ @integration_test = integration_test
31
+ @integration_test.meta.attr_accessor :response
32
+ end
33
+
34
+ [:get, :post, :put, :delete].each do |verb|
35
+ define_method(verb) do |url, *args|
36
+ integration_test.send(verb, url, *args)
37
+ process integration_test.response, verb, url, *args
38
+ end
39
+ end
40
+
41
+ def xhr(verb, url, *args)
42
+ integration_test.send(:xhr, verb, url, *args)
43
+ process integration_test.response, verb, url, *args
44
+ end
45
+
46
+ def process(response, verb, url, *args)
47
+ if verb == :get && response.code == '302'
48
+ location = response.headers['Location']
49
+
50
+ if location =~ /#{url}$/ # Schema change
51
+ integration_test.https!(!!(location =~ /^https/))
52
+ response = send(verb, url, *args)
53
+ elsif location =~ /#!?/ # AJAX load
54
+ response = send(:xhr, verb, url, *args)
55
+ end
56
+
57
+ elsif response.code == '404'
58
+ if File.exist?(static_content_path(url))
59
+ case ext = File.extension(url)
60
+ when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf|ico/
61
+ response.body = static_content_file(url)
62
+ response.headers["type"] = "text/#{ext}" # readable as response.content_type
63
+ response.meta.attr_accessor :code
64
+ response.code = "200"
65
+ else
66
+ log "Skipping unknown type #{url}"
67
+ end
68
+ end
69
+ end
70
+
71
+ # don't count on metaclass taking block, e.g.
72
+ # http://relevancellc.com/2008/2/12/how-should-metaclass-work
73
+ response.metaclass.class_eval do
74
+ include Relevance::CoreExtensions::Response
75
+ end
76
+
77
+ return response
78
+ end
79
+
80
+ def static_content_file(url)
81
+ File.read(static_content_path(url))
82
+ end
83
+
84
+ def static_content_path(url)
85
+ File.expand_path(File.join(rails_root, "public", url))
86
+ end
87
+ end
@@ -0,0 +1,12 @@
1
+ module Recording
2
+ def self.stderr
3
+ $stderr = recorder = StringIO.new
4
+ begin
5
+ yield
6
+ ensure
7
+ $stderr = STDERR
8
+ end
9
+ recorder.rewind
10
+ recorder.read
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # Used to create a stub response when we didn't get back a real response
2
+ class Relevance::Tarantula::Response
3
+ HASHABLE_ATTRS = [:code, :body, :content_type]
4
+ attr_accessor *HASHABLE_ATTRS
5
+
6
+ def initialize(hash)
7
+ hash.each do |k,v|
8
+ raise ArgumentError, k unless HASHABLE_ATTRS.member?(k)
9
+ self.instance_variable_set("@#{k}", v)
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,77 @@
1
+ class Relevance::Tarantula::Result
2
+ HASHABLE_ATTRS = [:success, :method, :url, :response, :referrer, :data, :description, :log, :test_name]
3
+ DEFAULT_LOCALHOST = "http://localhost:3000"
4
+ attr_accessor *HASHABLE_ATTRS
5
+ include Relevance::Tarantula
6
+ include Relevance::Tarantula::HtmlReportHelper
7
+
8
+ def initialize(hash)
9
+ hash.each do |k,v|
10
+ raise ArgumentError, k unless HASHABLE_ATTRS.member?(k)
11
+ self.instance_variable_set("@#{k}", v)
12
+ end
13
+ end
14
+
15
+ def short_description
16
+ [method,url].join(" ")
17
+ end
18
+
19
+ def sequence_number
20
+ @sequence_number ||= (self.class.next_number += 1)
21
+ end
22
+
23
+ def file_name
24
+ "#{sequence_number}.html"
25
+ end
26
+
27
+ def code
28
+ response && response.code
29
+ end
30
+
31
+ def body
32
+ response && response.body
33
+ end
34
+
35
+ def full_url
36
+ "#{DEFAULT_LOCALHOST}#{url}"
37
+ end
38
+
39
+ ALLOW_NNN_FOR = /^allow_(\d\d\d)_for$/
40
+
41
+ class << self
42
+ attr_accessor :next_number
43
+
44
+ def handle(result)
45
+ retval = result.dup
46
+ retval.success = successful?(result.response) || can_skip_error?(result)
47
+ retval.description = "Bad HTTP Response" unless retval.success
48
+ retval
49
+ end
50
+
51
+ def success_codes
52
+ %w{200 201 302 401}
53
+ end
54
+
55
+ # allow_errors_for is a hash
56
+ # k=error code,
57
+ # v=array of matchers for urls that can skip said error
58
+ attr_accessor :allow_errors_for
59
+ def can_skip_error?(result)
60
+ coll = allow_errors_for[result.code]
61
+ return false unless coll
62
+ coll.any? {|item| item === result.url}
63
+ end
64
+
65
+ def successful?(response)
66
+ success_codes.member?(response.code)
67
+ end
68
+
69
+ def method_missing(meth, *args)
70
+ super unless ALLOW_NNN_FOR =~ meth.to_s
71
+ (allow_errors_for[$1] ||= []).push(*args)
72
+ end
73
+ end
74
+
75
+ self.allow_errors_for = {}
76
+ self.next_number = 0
77
+ end
@@ -0,0 +1,32 @@
1
+ <div id="<%= test_name %>">
2
+ <% %w{failures successes}.each do |result_type| %>
3
+ <table class="list tablesorter" cellspacing="0">
4
+ <caption><%= send(result_type).size %> <%= result_type.capitalize %></caption>
5
+ <thead>
6
+ <tr>
7
+ <th class="sort asc"><span>URL</span><span class="sort">&nbsp;</span></th>
8
+ <th><span>Action</span><span class="sort">&nbsp;</span></th>
9
+ <th><span>Response</span><span class="sort">&nbsp;</span></th>
10
+ <th class="left"><span>Description</span><span class="sort">&nbsp;</span></th>
11
+ <th><span>Referrer</span><span class="sort">&nbsp;</span></th>
12
+ </tr>
13
+ </thead>
14
+ <tfoot>
15
+ <tr><td colspan="5">&nbsp;</td></tr>
16
+ </tfoot>
17
+
18
+ <tbody>
19
+ <% send(result_type).sort{|x,y| y.code.to_s <=> x.code.to_s}.each_with_index do |result,i| %>
20
+ <tr class="<%= (i%2 == 0) ? 'even' : 'odd' %>">
21
+ <td class="left"><a href="<%= "#{test_name}/#{result.file_name}" %>"><%= result.url.ellipsize(50) %></a></td>
22
+ <td class="method"><%= result.method.to_s.upcase %></td> <!-- TODO Clean up demeter violation -->
23
+ <td><span class="<%= class_for_code(result.code) %>"><%= result.code %></span></td>
24
+ <td class="left"><%= result.description %></td>
25
+ <td class="left"><%= result.referrer.ellipsize(30) %></td>
26
+ </tr>
27
+ <% end %>
28
+ </tbody>
29
+ </table>
30
+ <br/>
31
+ <% end %>
32
+ </div>
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ begin
3
+ gem 'tidy'
4
+ require 'tidy'
5
+ rescue Gem::LoadError
6
+ puts "Tidy gem not available -- 'gem install tidy' to get it."
7
+ end
8
+
9
+ if defined? Tidy
10
+ Tidy.path = ENV['TIDY_PATH'] if ENV['TIDY_PATH']
11
+
12
+ class Relevance::Tarantula::TidyHandler
13
+ include Relevance::Tarantula
14
+ def initialize(options = {})
15
+ @options = {:show_warnings=>true}.merge(options)
16
+ end
17
+ def handle(result)
18
+ response = result.response
19
+ return unless response.html?
20
+ tidy = Tidy.open(@options) do |tidy|
21
+ xml = tidy.clean(response.body)
22
+ tidy
23
+ end
24
+ unless tidy.errors.blank?
25
+ error_result = result.dup
26
+ error_result.description = "Bad HTML (Tidy)"
27
+ error_result.data = tidy.errors.inspect
28
+ error_result
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ class Relevance::Tarantula::Transform
2
+ attr_accessor :from, :to
3
+ def initialize(from, to)
4
+ @from = from
5
+ @to = to
6
+ end
7
+ def [](string)
8
+ case to
9
+ when Proc
10
+ string.gsub(from, &to)
11
+ else
12
+ string.gsub(from, to)
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+
3
+ namespace :tarantula do
4
+
5
+ desc 'Run tarantula tests.'
6
+ task :test do
7
+ rm_rf "tmp/tarantula"
8
+ Rake::TestTask.new(:tarantula_test) do |t|
9
+ t.libs << 'test'
10
+ t.pattern = 'test/tarantula/**/*_test.rb'
11
+ t.verbose = true
12
+ end
13
+
14
+ Rake::Task[:tarantula_test].invoke
15
+ end
16
+
17
+ desc 'Run tarantula tests and open results in your browser.'
18
+ task :report do
19
+ begin
20
+ Rake::Task['tarantula:test'].invoke
21
+ rescue RuntimeError => e
22
+ puts e.message
23
+ end
24
+
25
+ Dir.glob("tmp/tarantula/**/index.html") do |file|
26
+ if PLATFORM['darwin']
27
+ system("open #{file}")
28
+ elsif PLATFORM[/linux/]
29
+ system("firefox #{file}")
30
+ else
31
+ puts "You can view tarantula results at #{file}"
32
+ end
33
+ end
34
+ end
35
+
36
+ desc 'Generate a default tarantula test'
37
+ task :setup do
38
+ mkdir_p "test/tarantula"
39
+ template_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "template", "tarantula_test.rb"))
40
+ cp template_path, "test/tarantula/"
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ require "#{File.dirname(__FILE__)}/../test_helper"
2
+ require "relevance/tarantula"
3
+
4
+ class TarantulaTest < ActionController::IntegrationTest
5
+ # Load enough test data to ensure that there's a link to every page in your
6
+ # application. Doing so allows Tarantula to follow those links and crawl
7
+ # every page. For many applications, you can load a decent data set by
8
+ # loading all fixtures.
9
+ fixtures :all
10
+
11
+ def test_tarantula
12
+ # If your application requires users to log in before accessing certain
13
+ # pages, uncomment the lines below and update them to allow this test to
14
+ # log in to your application. Doing so allows Tarantula to crawl the
15
+ # pages that are only accessible to logged-in users.
16
+ #
17
+ # post '/session', :login => 'quentin', :password => 'monkey'
18
+ # follow_redirect!
19
+
20
+ tarantula_crawl(self)
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,213 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: panmind-tarantula
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 3
10
+ version: 0.3.3
11
+ platform: ruby
12
+ authors:
13
+ - Relevance, Inc.
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-18 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: htmlentities
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 55
30
+ segments:
31
+ - 4
32
+ - 2
33
+ - 0
34
+ version: 4.2.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: hpricot
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 61
46
+ segments:
47
+ - 0
48
+ - 8
49
+ - 1
50
+ version: 0.8.1
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: micronaut
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: log_buddy
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
81
+ description: A big hairy fuzzy spider that crawls your site, wreaking havoc
82
+ email: opensource@thinkrelevance.com
83
+ executables: []
84
+
85
+ extensions: []
86
+
87
+ extra_rdoc_files:
88
+ - LICENSE
89
+ - README.rdoc
90
+ files:
91
+ - CHANGELOG
92
+ - README.rdoc
93
+ - Rakefile
94
+ - VERSION.yml
95
+ - examples/example_helper.rb
96
+ - examples/relevance/core_extensions/ellipsize_example.rb
97
+ - examples/relevance/core_extensions/file_example.rb
98
+ - examples/relevance/core_extensions/response_example.rb
99
+ - examples/relevance/core_extensions/test_case_example.rb
100
+ - examples/relevance/tarantula/attack_handler_example.rb
101
+ - examples/relevance/tarantula/basic_attack_example.rb
102
+ - examples/relevance/tarantula/crawler_example.rb
103
+ - examples/relevance/tarantula/form_example.rb
104
+ - examples/relevance/tarantula/form_submission_example.rb
105
+ - examples/relevance/tarantula/html_document_handler_example.rb
106
+ - examples/relevance/tarantula/html_report_helper_example.rb
107
+ - examples/relevance/tarantula/html_reporter_example.rb
108
+ - examples/relevance/tarantula/invalid_html_handler_example.rb
109
+ - examples/relevance/tarantula/io_reporter_example.rb
110
+ - examples/relevance/tarantula/link_example.rb
111
+ - examples/relevance/tarantula/log_grabber_example.rb
112
+ - examples/relevance/tarantula/rails_integration_proxy_example.rb
113
+ - examples/relevance/tarantula/result_example.rb
114
+ - examples/relevance/tarantula/tidy_handler_example.rb
115
+ - examples/relevance/tarantula/transform_example.rb
116
+ - examples/relevance/tarantula_example.rb
117
+ - laf/images/header_bg.jpg
118
+ - laf/images/logo.png
119
+ - laf/images/tagline.png
120
+ - laf/javascripts/jquery-1.2.3.js
121
+ - laf/javascripts/jquery-ui-tabs.js
122
+ - laf/javascripts/jquery.tablesorter.js
123
+ - laf/javascripts/tarantula.js
124
+ - laf/stylesheets/tarantula.css
125
+ - lib/relevance/core_extensions/ellipsize.rb
126
+ - lib/relevance/core_extensions/file.rb
127
+ - lib/relevance/core_extensions/metaclass.rb
128
+ - lib/relevance/core_extensions/response.rb
129
+ - lib/relevance/core_extensions/string_chars_fix.rb
130
+ - lib/relevance/core_extensions/test_case.rb
131
+ - lib/relevance/tarantula.rb
132
+ - lib/relevance/tarantula/attack.rb
133
+ - lib/relevance/tarantula/attack_handler.rb
134
+ - lib/relevance/tarantula/basic_attack.rb
135
+ - lib/relevance/tarantula/crawler.rb
136
+ - lib/relevance/tarantula/detail.html.erb
137
+ - lib/relevance/tarantula/form.rb
138
+ - lib/relevance/tarantula/form_submission.rb
139
+ - lib/relevance/tarantula/html_document_handler.rb
140
+ - lib/relevance/tarantula/html_report_helper.rb
141
+ - lib/relevance/tarantula/html_reporter.rb
142
+ - lib/relevance/tarantula/index.html.erb
143
+ - lib/relevance/tarantula/invalid_html_handler.rb
144
+ - lib/relevance/tarantula/io_reporter.rb
145
+ - lib/relevance/tarantula/link.rb
146
+ - lib/relevance/tarantula/log_grabber.rb
147
+ - lib/relevance/tarantula/rails_integration_proxy.rb
148
+ - lib/relevance/tarantula/recording.rb
149
+ - lib/relevance/tarantula/response.rb
150
+ - lib/relevance/tarantula/result.rb
151
+ - lib/relevance/tarantula/test_report.html.erb
152
+ - lib/relevance/tarantula/tidy_handler.rb
153
+ - lib/relevance/tarantula/transform.rb
154
+ - tasks/tarantula_tasks.rake
155
+ - template/tarantula_test.rb
156
+ - LICENSE
157
+ has_rdoc: true
158
+ homepage: http://github.com/Panmind/tarantula
159
+ licenses: []
160
+
161
+ post_install_message:
162
+ rdoc_options:
163
+ - --charset=UTF-8
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ none: false
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ hash: 3
181
+ segments:
182
+ - 0
183
+ version: "0"
184
+ requirements: []
185
+
186
+ rubyforge_project:
187
+ rubygems_version: 1.3.7
188
+ signing_key:
189
+ specification_version: 3
190
+ summary: A big hairy fuzzy spider that crawls your site, wreaking havoc
191
+ test_files:
192
+ - examples/example_helper.rb
193
+ - examples/relevance/core_extensions/ellipsize_example.rb
194
+ - examples/relevance/core_extensions/file_example.rb
195
+ - examples/relevance/core_extensions/response_example.rb
196
+ - examples/relevance/core_extensions/test_case_example.rb
197
+ - examples/relevance/tarantula/attack_handler_example.rb
198
+ - examples/relevance/tarantula/basic_attack_example.rb
199
+ - examples/relevance/tarantula/crawler_example.rb
200
+ - examples/relevance/tarantula/form_example.rb
201
+ - examples/relevance/tarantula/form_submission_example.rb
202
+ - examples/relevance/tarantula/html_document_handler_example.rb
203
+ - examples/relevance/tarantula/html_report_helper_example.rb
204
+ - examples/relevance/tarantula/html_reporter_example.rb
205
+ - examples/relevance/tarantula/invalid_html_handler_example.rb
206
+ - examples/relevance/tarantula/io_reporter_example.rb
207
+ - examples/relevance/tarantula/link_example.rb
208
+ - examples/relevance/tarantula/log_grabber_example.rb
209
+ - examples/relevance/tarantula/rails_integration_proxy_example.rb
210
+ - examples/relevance/tarantula/result_example.rb
211
+ - examples/relevance/tarantula/tidy_handler_example.rb
212
+ - examples/relevance/tarantula/transform_example.rb
213
+ - examples/relevance/tarantula_example.rb