fluoride-analyzer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 29f99f8f8b407486d27622bb63af1b8bd604d87f
4
+ data.tar.gz: b29dacf810a25eb37374ac88532f2c09217cdd65
5
+ SHA512:
6
+ metadata.gz: f6c30d82f0adbc6051ee083d9062233bd8a632832b343647acad1c97cd7a82fbb1308a11a4959be511ba29d648c859f84dd2964ffa05c8992d34bdabd8b14c93
7
+ data.tar.gz: 7c618c9bf042e2319e0ccb95a0fb00338a82a0daa4088827b0573df89748f0b7f0340f2cba3bf44051158a0ea1dbcc7bbf67869bf469ea428121b50b58a2430f
@@ -0,0 +1,14 @@
1
+ module Fluoride
2
+ module Analyzer
3
+ class ConfigurationError < ::StandardError
4
+ end
5
+ end
6
+ end
7
+
8
+ require 'fluoride-analyzer/config'
9
+ require 'fluoride-analyzer/request'
10
+ require 'fluoride-analyzer/request-processor'
11
+ require 'fluoride-analyzer/exchange-result'
12
+ require 'fluoride-analyzer/exception-result'
13
+ require 'fluoride-analyzer/result-collection'
14
+ require 'fluoride-analyzer/rails' if defined?(Rails)
@@ -0,0 +1,43 @@
1
+ module Fluoride::Analyzer
2
+ class Config
3
+ require 'yaml'
4
+
5
+ DEFAULT_CONFIG_PATH = '.fluoride.yml'
6
+ DEFAULT_EXCLUDE_PATHS = [ %r[^/images], %r[^/stylesheets], %r[^/javascripts], %r[^/system], ]
7
+ DEFAULT_EXCLUDE_MIME_TYPES = [ %r[image], %r[text/css], %r[javascript], %r[shockwave] ]
8
+
9
+ attr_accessor :exclude_path_patterns,
10
+ :exclude_mime_types,
11
+ :match_on_required_params,
12
+ :exclude_match_params,
13
+ :limit_count
14
+
15
+
16
+ def self.load(config_path = DEFAULT_CONFIG_PATH)
17
+ yaml_config = YAML::load(File.open(config_path))
18
+ config = self.new(yaml_config)
19
+ end
20
+
21
+ def initialize(yaml_config)
22
+ self.exclude_path_patterns = DEFAULT_EXCLUDE_PATHS
23
+ + yaml_config['exclude_path_patterns']
24
+ - yaml_config['include_path_patterns']
25
+
26
+ self.exclude_mime_types = DEFAULT_EXCLUDE_MIME_TYPES
27
+ + yaml_config['exclude_mime_types']
28
+ - yaml_config['include_mime_types']
29
+
30
+
31
+ if yaml_config.has_key?('match_on_required_params')
32
+ self.match_on_required_params = yaml_config['match_on_required_params']
33
+ else
34
+ self.match_on_required_params = false
35
+ end
36
+
37
+ self.exclude_match_params = yaml_config['exclude_match_params'] || []
38
+ self.include_match_params = yaml_config['include_match_params'] || []
39
+ self.limit_count = yaml_config['limit_count']
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,5 @@
1
+ require 'fluoride-analyzer'
2
+ module Fluoride::Analyzer
3
+ class ExceptionResult
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'fluoride-analyzer'
2
+ module Fluoride::Analyzer
3
+ class ExchangeResult
4
+ end
5
+ end
@@ -0,0 +1,51 @@
1
+ require 'fluoride-analyzer/group-context'
2
+
3
+ module Fluoride::Analyzer
4
+ class GroupCollapser
5
+ def initialize(pattern, letname_map, method, status, requests_list)
6
+ @pattern = pattern
7
+ @letname_map = letname_map
8
+ @request_list = requests_list
9
+ @method, @status = method, status
10
+ end
11
+ attr_reader :method, :status, :letname_map
12
+
13
+ def stet_list
14
+ []
15
+ end
16
+
17
+ def requests
18
+ @request_list
19
+ end
20
+
21
+ def reduce_path(path, request)
22
+ path = @pattern.dup
23
+ request['path_params'].each_pair do |name, value|
24
+ next if stet_list.include?(name)
25
+ target_name = letname_map.fetch(name, name)
26
+ path.sub!(/:#{name}/,"\#{#{target_name}}")
27
+ end
28
+ path
29
+ end
30
+
31
+ def reduce_query(query, request)
32
+ ""
33
+ #none captured (yet?)
34
+ end
35
+
36
+ def each_group_context
37
+ path_tuples = requests.map do |request|
38
+ [request['path'], request['query_params'], request]
39
+ end
40
+
41
+ reduced_hash = Hash.new{|h,k| h[k] = []}
42
+ path_tuples.each do |path, query, request|
43
+ reduced_hash[ [ reduce_path(path, request), reduce_query(query, request) ] ] << request
44
+ end
45
+
46
+ reduced_hash.each do |(path, query_params), requests|
47
+ yield GroupContext.new(method, status, requests, path, query_params)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,86 @@
1
+ require 'fluoride-analyzer'
2
+
3
+ module Fluoride::Analyzer
4
+ class GroupContext
5
+ def initialize(method, status, requests, path, query_params)
6
+ @method, @status_code, @requests, @path, @query_params = method, status, requests, path, query_params
7
+ end
8
+ attr_reader :method, :status_code
9
+
10
+ def test_method
11
+ @method.downcase
12
+ end
13
+
14
+ def status_description
15
+ case @status_code.to_i
16
+ when 300..399
17
+ "Redirect"
18
+ else
19
+ "OK"
20
+ end
21
+ end
22
+
23
+ def request_count
24
+ @requests.inject(0) do |sum, request|
25
+ sum + request['sources'].keys.length
26
+ end
27
+ end
28
+
29
+ def example_source
30
+ request['sources'].keys.first
31
+ end
32
+
33
+ def example_path
34
+ request['path']
35
+ end
36
+
37
+ def request_spec_description
38
+ "#@method #{spec_request_path}"
39
+ end
40
+
41
+ def should_what
42
+ case @status_code.to_i
43
+ when 300..399
44
+ "redirect"
45
+ else
46
+ "succeed"
47
+ end
48
+ end
49
+
50
+ def redirect_path
51
+ request['redirect_location'].sub(%r[^https?://#{request['host']}], '')
52
+ end
53
+
54
+ def test_result
55
+ case @status_code.to_i
56
+ when 300..399
57
+ ["response.should redirect_to(\"#{redirect_path}\")"]
58
+ else
59
+ ["response.should be_success", "response.status.should == 200"]
60
+ end
61
+ end
62
+
63
+ def test_request(indent)
64
+ indent = " " * indent
65
+ test_request = "#{test_method} \"#{spec_request_path}\""
66
+ if request.has_key? 'post_params'
67
+ params = request['post_params'].pretty_inspect.split("\n")
68
+ params = ([params[0]] + params[1..-1].map do |line|
69
+ indent + line
70
+ end).join("\n")
71
+ test_request += ", #{params}"
72
+ end
73
+ test_request
74
+ end
75
+
76
+ def spec_request_path
77
+ "#{@path}#{@query_params}"
78
+ end
79
+
80
+ private
81
+
82
+ def request
83
+ @requests.first
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,261 @@
1
+ require 'fluoride-analyzer'
2
+ require 'rack'
3
+ require 'yaml'
4
+ #Also: Rails and ActionDispatch::Request
5
+
6
+ module Fluoride::Analyzer
7
+ class Parser
8
+ attr_accessor :files, :limit, :target_path
9
+ attr_reader :exceptions, :results, :counts
10
+
11
+ def initialize
12
+ @exceptions = []
13
+ @counts = {
14
+ :excluded => 0,
15
+ :unrecognized => 0,
16
+ :no_matching_route => 0,
17
+ :exceptions => 0
18
+ }
19
+ @results = Hash.new do|results, pattern| #PATH PATTERN
20
+ results[pattern] = Hash.new do |by_method, method| #METHOD
21
+ by_method[method] = Hash.new do |records, status| #STATUS CODE
22
+ records[status] = Hash.new do |record, key| #formatted record
23
+ record[key] = []
24
+ end
25
+ end
26
+ end
27
+ end
28
+ @limit = -1
29
+ end
30
+
31
+ def excluded_content_types
32
+ [ %r[image], %r[text/css], %r[javascript], %r[shockwave] ]
33
+ end
34
+
35
+ def excluded_paths
36
+ [ %r[^/images], %r[\.ttf\z], %r[\.woff\z] ]
37
+ end
38
+
39
+ def exclude?(record)
40
+ return true if record['type'] == 'exception_raised'
41
+
42
+ if excluded_content_types.any?{ |reg| reg =~ record['response']['headers']['Content-Type'] }
43
+ return true
44
+ end
45
+ if excluded_paths.any?{|req| req =~ record['request']['path']}
46
+ return true
47
+ end
48
+ return false
49
+ rescue
50
+ warn "Exception raised while filtering record: #{record.inspect}"
51
+ raise
52
+ end
53
+
54
+ def format_record(record, path_params)
55
+ {
56
+ 'path' => record['request']['path'],
57
+ 'query_params' => record['request']['query_params'],
58
+ 'content-type' => record['request']['content_type'],
59
+ 'path_params' => path_params,
60
+ 'redirect_location' => record['response']['headers']['Location'],
61
+ 'host' => record['request']['host']
62
+ #'accept' => record['request']['accept']
63
+ }
64
+ end
65
+
66
+ def formatted_results
67
+ formatted = {}
68
+ results.each do |pattern, methods|
69
+ frmt_methods = formatted[pattern] = {}
70
+ methods.each do |method, status|
71
+ frmt_statuses = frmt_methods[method] = {}
72
+ status.each do |code, requests|
73
+ frmt_statuses[code] = requests.keys.map do |req_hash|
74
+ hash = req_hash.dup
75
+ hash['sources'] = Hash[requests[req_hash]]
76
+ hash
77
+ end
78
+ end
79
+ end
80
+ end
81
+ formatted
82
+ end
83
+
84
+ def post_params(record)
85
+ return {} unless %w{POST PUT}.include?(record['request']['method'])
86
+ unless record['request']['content_type'].nil? or
87
+ %r[^application/x-www-form-urlencoded.*] =~ record['request']['content_type']
88
+ return {}
89
+ end
90
+
91
+ form_hash = Rack::Utils.parse_nested_query(record['request']['body'])
92
+
93
+ { 'post_params' => form_hash }
94
+ end
95
+
96
+ RoutePattern = Struct.new(:route, :matches, :params, :path_spec, :segment_keys)
97
+
98
+ class Patterner
99
+ def self.for(rails_routes)
100
+ if rails_routes.respond_to? :recognize_path
101
+ Rails4.new(rails_routes)
102
+ else
103
+ Rails3.new(rails_routes)
104
+ end
105
+ end
106
+
107
+ def base_env
108
+ @base_env ||= {
109
+ "HTTP_REFERER" => '',
110
+ "HTTP_COOKIE" => '',
111
+ "HTTP_AUTHORIZATION" => '',
112
+ "REQUEST_METHOD" => "GET",
113
+ 'HTTP_HOST' => '',
114
+ 'SERVER_NAME' => '',
115
+ 'SERVER_ADDR' => '',
116
+ 'SERVER_PORT' => '80',
117
+ "SCRIPT_NAME" => '',
118
+ "QUERY_STRING" => '',
119
+ 'rack.input' => '' #body
120
+ }
121
+ end
122
+
123
+ def initialize(rails_routes)
124
+ @rails_routes = rails_routes
125
+ end
126
+ attr_reader :rails_routes
127
+
128
+ def build_request(result_env)
129
+ ActionDispatch::Request.new(base_env.merge(request_env))
130
+ end
131
+
132
+ def route_map
133
+ @route_map ||=
134
+ begin
135
+ ad_routes_array = rails_routes.routes
136
+ rack_routes_array = rails_routes.set.instance_eval{ @routes }
137
+ Hash[ rack_routes_array.zip(ad_routes_array) ]
138
+ end
139
+ end
140
+
141
+ def route_set
142
+ @route_set ||=
143
+ begin
144
+ set = rails_routes.set
145
+ set
146
+ end
147
+ end
148
+
149
+ class Rails3 < Patterner
150
+ def build(env)
151
+ req = build_request(env)
152
+ route, matches, params = route_set.recognize(req)
153
+
154
+ path_spec = :unrecognized
155
+ segment_keys = {}
156
+
157
+ if route_map.has_key?(route)
158
+ rails_route = route_map[route]
159
+ path_spec = rails_route.path
160
+ segment_keys = rails_route.segment_keys
161
+ end
162
+
163
+ RoutePattern.new(route, matches, params, path_spec, segment_keys)
164
+ end
165
+ end
166
+
167
+ class Rails4 < Patterner
168
+ def route_set
169
+ @route_set ||=
170
+ begin
171
+ set = Rails.application.routes.router
172
+ set
173
+ end
174
+ end
175
+
176
+ def build_request(request_env)
177
+ ActionDispatch::Request.new(base_env.merge(request_env))
178
+ end
179
+
180
+ def build(env)
181
+ req = build_request(env)
182
+ pattern = nil
183
+ route_set.recognize(req) do |route, matches, params|
184
+ rails_route = route_map[route]
185
+
186
+ path_spec = :unrecognized
187
+ segment_keys = {}
188
+
189
+ if route_map.has_key?(route)
190
+ rails_route = route_map[route]
191
+ path_spec = rails_route.path.spec.to_s
192
+ segment_keys = rails_route.segment_keys
193
+ end
194
+
195
+ pattern = RoutePattern.new(route, matches, params, path_spec, segment_keys)
196
+ end
197
+ if pattern.nil?
198
+ pattern = RoutePattern.new(nil,nil,nil,nil,nil)
199
+ end
200
+ pattern
201
+ end
202
+ end
203
+ end
204
+
205
+ def patterner
206
+ @patterner ||= Patterner.for(Rails.application.routes)
207
+ end
208
+
209
+ def collect_record(file, record, index)
210
+ if exclude?(record)
211
+ @counts[:excluded] += 1
212
+ return
213
+ end
214
+
215
+ request_env = {
216
+ "REQUEST_METHOD" => record['request']['method'].to_s.upcase,
217
+ "PATH_INFO" => record['request']['path'],
218
+ }
219
+ unless request_env['REQUEST_METHOD'] == "GET"
220
+ request_env['rack.input'] = StringIO.new(record['request']['body'])
221
+ end
222
+
223
+ pattern = patterner.build(request_env)
224
+
225
+ route = pattern.route
226
+
227
+ if route.nil?
228
+ @counts[:unrecognized] += 1
229
+ return
230
+ end
231
+
232
+ if pattern.path_spec == :unrecognized
233
+ @counts[:no_matching_route] += 1
234
+ warn "Unrecognized route: #{record['request']['path'].inspect}"
235
+ else
236
+ route_path = pattern.path_spec
237
+ path_params = Hash[pattern.segment_keys.map do |key|
238
+ [key, params[key]]
239
+ end]
240
+ end
241
+
242
+ formatted_record = format_record(record, path_params).merge(post_params(record))
243
+
244
+ self.results[route_path][record['request']['method']][record['response']['status']][formatted_record] << [file, index]
245
+ end
246
+
247
+ def parse_stream(file, string)
248
+ stream = YAML.load_stream(string)
249
+ stream = stream.documents if stream.respond_to? :documents
250
+
251
+ stream.each_with_index do |record, index|
252
+ collect_record(file, record, index)
253
+ end
254
+ rescue ArgumentError => ex
255
+ @exceptions << [ex, file]
256
+ rescue Exception => ex
257
+ @exceptions << [ex, file]
258
+ raise
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,30 @@
1
+ module Fluoride::Analyzer
2
+ class PatternCollapser
3
+ def initialize(pattern, methods_hash)
4
+ @pattern = pattern
5
+ @methods_hash = methods_hash
6
+ end
7
+
8
+ def erase_list
9
+ %w{ format }
10
+ end
11
+
12
+ def pattern
13
+ erase_list.inject(@pattern) do |pattern, erase|
14
+ pattern.sub(/\(.:#{erase}\)/,'')
15
+ end
16
+ end
17
+
18
+ def param_letname_map
19
+ { :id => :model_id }
20
+ end
21
+
22
+ def params_fields
23
+ @methods_hash.values.first.values.first.first['path_params'].keys.reject do |key|
24
+ key == :format
25
+ end.map do |name|
26
+ param_letname_map.fetch(name, name)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ require 'fluoride-analyzer/group-collapser'
2
+ require 'fluoride-analyzer/pattern-collapser'
3
+
4
+ module Fluoride::Analyzer
5
+ class PatternContext
6
+ def initialize(pattern, methods_hash)
7
+ @pattern, @methods_hash = pattern, methods_hash
8
+ @collapser = PatternCollapser.new(pattern, methods_hash)
9
+ end
10
+ attr_reader :pattern
11
+
12
+ def each_status_group
13
+ @methods_hash.each_pair do |method, hash|
14
+ hash.each_pair do |status, requests|
15
+ GroupCollapser.new(@collapser.pattern, @collapser.param_letname_map, method, status, requests).each_group_context do |context|
16
+ yield context
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def param_fields
23
+ @collapser.params_fields
24
+ end
25
+
26
+ def filename
27
+ @collapser.pattern.gsub(%r{[:/().]+},'_').gsub(/^_|_$/, '') + "_spec.rb"
28
+ end
29
+
30
+ def context_binding
31
+ binding
32
+ end
33
+ end
34
+ end
@@ -0,0 +1 @@
1
+ require 'fluoride-analyzer/rails/railtie'
@@ -0,0 +1,14 @@
1
+ require 'fluoride-analyzer'
2
+
3
+ module Fluoride
4
+ module Analyzer
5
+ class Railtie < ::Rails::Railtie
6
+ #config.fluoride.directory = "fluoride-collector"
7
+
8
+ rake_tasks do
9
+ # load '/path/to/task'
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require 'fluoride-analyzer'
2
+
3
+ module Fluoride::Analyzer
4
+ class RequestProcessor
5
+ end
6
+ end
7
+
@@ -0,0 +1,26 @@
1
+ require 'erb'
2
+ require 'fluoride-analyzer/pattern-context'
3
+
4
+ module Fluoride::Analyzer
5
+ class RequestTemplater
6
+ def initialize
7
+
8
+ end
9
+ attr_accessor :template, :template_string, :target_dir, :results
10
+
11
+ def template
12
+ @template ||= ERB.new(template_string, nil, '<>')
13
+ end
14
+
15
+ def go
16
+ results.each_pair do |pattern, statuses|
17
+ context = PatternContext.new(pattern, statuses)
18
+
19
+ path = File.join(context.filename)
20
+ contents = template.result(context.context_binding)
21
+
22
+ yield(path, contents)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ require 'fluoride-analyzer'
2
+
3
+ module Fluoride::Analyzer
4
+ class Request
5
+ attr_accessor :request_hash
6
+
7
+ def initialize
8
+ @request_hash = {}
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'fluoride-analyzer'
2
+ module Fluoride::Analyzer
3
+ class ResultCollection
4
+ end
5
+ end
@@ -0,0 +1,46 @@
1
+ require 'fluoride-analyzer/request-templater'
2
+
3
+ FLUORIDE_PATH = 'fluoride-collector'
4
+ LIMIT = 2000
5
+
6
+ directory 'spec/requests'
7
+
8
+ task :parse_fluoride => 'paths.yml'
9
+
10
+ task :rebuild_request_specs => [:clobber_request_specs, :template_request_specs]
11
+
12
+ task :clobber_request_specs do
13
+ sh("rm -rf spec/requests/*")
14
+ end
15
+
16
+ file 'results.yml' => FileList[ "#{FLUORIDE_PATH}/*.yml" ] do |task|
17
+ Rake::Task[:environment].invoke
18
+ parser = Fluoride::Analyzer::Parser.new
19
+
20
+ task.prerequisites.find_all do |prereq|
21
+ next unless File.file?(prereq) && __FILE__ != prereq
22
+ parser.parse_stream(File.read(prereq))
23
+ end
24
+
25
+ #parser.limit = LIMIT #XXX Uncomment to limit number of files parsed
26
+ parser.target_path = task.name
27
+
28
+ File.open(task.name, "w") do |target_file|
29
+ target_file.write(YAML.dump(parser.formatted_results))
30
+ end
31
+
32
+ puts "Found #{parser.formatted_results.keys.length} unique requests"
33
+ end
34
+
35
+ task :template_request_specs => ['spec/requests', 'results.yml'] do
36
+ templater = Fluoride::Analyzer::RequestTemplater.new
37
+
38
+ templater.template_string = File::read(File::expand_path("../../../templates/request_spec.erb", __FILE__))
39
+ templater.results = YAML.load(File.read('results.yml'))
40
+ templater.go do |filename, contents|
41
+ path = File.join("spec/requests", filename)
42
+ File.open(path, "w") do |spec_file|
43
+ spec_file.write(contents)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ puts Dir::pwd
2
+ require 'test/unit'
3
+ begin
4
+ require 'spec'
5
+ rescue LoadError
6
+ false
7
+ end
8
+
9
+ class RSpecTest < Test::Unit::TestCase
10
+ def test_that_rspec_is_available
11
+ assert_nothing_raised("\n\n * RSpec isn't available - please run: gem install rspec *\n\n"){ ::Spec }
12
+ end
13
+
14
+ def test_that_specs_pass
15
+ assert(system(*%w{spec -f e -p **/*.rb spec}),"\n\n * Specs failed *\n\n")
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ require "action_controller/railtie"
2
+ require 'fluoride-analyzer/rails'
3
+
4
+ describe Fluoride::Analyzer::Railtie do
5
+
6
+ def config(app)
7
+
8
+ end
9
+
10
+ let :rails_application do
11
+ Class.new(::Rails::Application).tap do |app|
12
+ app.configure do
13
+ config.active_support.deprecation = :stderr
14
+ config.eager_load = false
15
+ end
16
+ config(app)
17
+ app.initialize!
18
+ end
19
+ end
20
+
21
+ after :each do
22
+ Rails.application = nil #because Rails has ideas of it's own, silly thing
23
+ end
24
+
25
+ it "should add rake tasks"
26
+
27
+ end
@@ -0,0 +1,110 @@
1
+ require 'action_controller/railtie'
2
+ require 'fluoride-analyzer/parser'
3
+
4
+ describe Fluoride::Analyzer::Parser do
5
+ def config(app)
6
+ app.routes.draw do
7
+ get "/", :to => 'root#index', :as => :root
8
+ end
9
+ end
10
+
11
+ let! :rails_application do
12
+ Class.new(::Rails::Application).tap do |app|
13
+ app.configure do
14
+ config.active_support.deprecation = :stderr
15
+ config.eager_load = false
16
+ end
17
+ config(app)
18
+ app.initialize!
19
+ end
20
+ end
21
+
22
+ after :each do
23
+ Rails.application = nil
24
+ end
25
+
26
+ let :requests_stream do
27
+ YAML::dump_stream(*requests)
28
+ end
29
+
30
+ let :parser do
31
+ Fluoride::Analyzer::Parser.new.tap do |parser|
32
+ parser.parse_stream("test-file.yaml", requests_stream)
33
+ end
34
+ end
35
+
36
+ let :results do
37
+ parser.formatted_results
38
+ end
39
+
40
+ let :requests do
41
+ [
42
+ {"type"=>"normal_exchange",
43
+ "tags"=>nil,
44
+ "request"=>
45
+ {"query_string"=>"",
46
+ "body"=>"",
47
+ "method"=>"GET",
48
+ "accept"=>
49
+ "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
50
+ "content_type"=>nil,
51
+ "user_agent"=>
52
+ "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36",
53
+ "referer"=>nil,
54
+ "host"=>"0.0.0.0:3000",
55
+ "authorization"=>nil,
56
+ "cookies"=>nil,
57
+ "path"=>"/",
58
+ "accept_encoding"=>"gzip,deflate,sdch"},
59
+ "response"=>
60
+ {"body"=>
61
+ ["<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\n<!--\n\tsomebody@gmail.com june 2014\n-->\n\n\t<meta charset=\"utf-8\" />\n\t<title>Application</title>\n\t<meta name=\"viewport\" content=\"width=device-width, initial-sc"],
62
+ "status"=>200,
63
+ "headers"=>
64
+ {"Content-Type"=>"text/html; charset=utf-8",
65
+ "ETag"=>"\"5ff1d9c9172424e5d906216dcdacd9ef\"",
66
+ "X-UA-Compatible"=>"IE=Edge,chrome=1",
67
+ "Cache-Control"=>"max-age=0, private, must-revalidate",
68
+ "X-Runtime"=>"0.873536"}}
69
+ },
70
+
71
+ {"type"=>"normal_exchange",
72
+ "tags"=>nil,
73
+ "request"=>
74
+ {"query_string"=>"",
75
+ "body"=>"",
76
+ "method"=>"GET",
77
+ "accept"=>"text/css,*/*;q=0.1",
78
+ "content_type"=>nil,
79
+ "user_agent"=>
80
+ "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36",
81
+ "referer"=>"http://0.0.0.0:3000/",
82
+ "host"=>"0.0.0.0:3000",
83
+ "authorization"=>nil,
84
+ "cookies"=>nil,
85
+ "path"=>"/stylesheets/2014-bootstrap.css",
86
+ "accept_encoding"=>"gzip,deflate,sdch"},
87
+ "response"=>
88
+ {"body"=>
89
+ ["/*! normalize.css v3.0.0 | MIT License | git.io/normalize */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%; }\n\nbody {\n margin: 0; }\n\narticle,\naside,\n"],
90
+ "status"=>200,
91
+ "headers"=>
92
+ {"Content-Length"=>"15835",
93
+ "Content-Type"=>"text/css",
94
+ "Last-Modified"=>"Sun, 29 Jun 2014 00:00:48 GMT"}},
95
+ }
96
+ ]
97
+ end
98
+
99
+ it "should have excluded 1 request" do
100
+ expect(parser.counts[:excluded]).to eq(1)
101
+ end
102
+
103
+ it "should have 0 unrecognized requests" do
104
+ expect(parser.counts[:unrecognized]).to eq(0)
105
+ end
106
+
107
+ it "should be a well formatted version of the results" do
108
+ expect(results).to match("/" => {"GET" => {200 => match([ a_hash_including("path" => "/") ])}})
109
+ end
110
+ end
@@ -0,0 +1,67 @@
1
+ require 'fluoride-analyzer/request-templater'
2
+
3
+ describe Fluoride::Analyzer::RequestTemplater do
4
+ let :template_string do
5
+ <<-EOT
6
+ require 'spec_helper'
7
+
8
+ describe '<%= pattern %>' do
9
+ <% param_fields.each do |field| %>
10
+ let :<%= field %> do
11
+ FactoryGirl.create(:<%= field %>).id
12
+ end
13
+ <%end%>
14
+ <% each_status_group do |group| %>
15
+
16
+ # HTTP status code: <%= group.status_code %> <%= group.status_description %>
17
+ # <%= group.request_count %> cases recorded by Fluoride
18
+ # See example: '<%= group.example_source %>'
19
+ # example path: <%= group.example_path %>
20
+ describe '<%= group.request_spec_description %>' do
21
+ it "should <%= group.should_what %>" do
22
+ <%= group.test_request(6) %>
23
+ <% group.test_result.each do |test_result_line| %>
24
+ <%= test_result_line %>
25
+ <% end %>
26
+ end
27
+ end
28
+ <%end%>
29
+ end
30
+ EOT
31
+ end
32
+
33
+ let :results do
34
+ YAML.load(File.read(File.expand_path("../../spec-help/fixtures/results.yml", __FILE__)))
35
+ end
36
+
37
+ let :templater do
38
+ Fluoride::Analyzer::RequestTemplater.new.tap do |tmplr|
39
+ tmplr.template_string = template_string
40
+ tmplr.results = results
41
+ end
42
+ end
43
+
44
+ let :templated_list do
45
+ templated_list = []
46
+ templater.go do |path, contents|
47
+ templated_list << [path, contents]
48
+ end
49
+ templated_list
50
+ end
51
+
52
+ let :paths do
53
+ templated_list.map{|path, _| path}
54
+ end
55
+
56
+ let :contents do
57
+ templated_list.map{|_, contents| contents}
58
+ end
59
+
60
+ it "should template once per result" do
61
+ expect(templated_list.length).to eq(results.keys.length)
62
+ end
63
+
64
+ it "should put the right stuff in contents" do
65
+ expect(contents).to all(match(/HTTP status code:/))
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluoride-analyzer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Judson Lester
8
+ - Evan Down
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-07-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mattock
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>'
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>'
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: valise
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>'
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>'
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ description: |2
43
+ Part of the Fluoride suite - tools for making your black box a bit whiter
44
+ email:
45
+ - nyarly@gmail.com
46
+ - evan@lrdesign.com
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - lib/fluoride-analyzer/parser.rb
52
+ - lib/fluoride-analyzer/exception-result.rb
53
+ - lib/fluoride-analyzer/rails/railtie.rb
54
+ - lib/fluoride-analyzer/group-context.rb
55
+ - lib/fluoride-analyzer/config.rb
56
+ - lib/fluoride-analyzer/request-templater.rb
57
+ - lib/fluoride-analyzer/group-collapser.rb
58
+ - lib/fluoride-analyzer/rails.rb
59
+ - lib/fluoride-analyzer/pattern-collapser.rb
60
+ - lib/fluoride-analyzer/request.rb
61
+ - lib/fluoride-analyzer/tasks.rake
62
+ - lib/fluoride-analyzer/result-collection.rb
63
+ - lib/fluoride-analyzer/request-processor.rb
64
+ - lib/fluoride-analyzer/pattern-context.rb
65
+ - lib/fluoride-analyzer/exchange-result.rb
66
+ - lib/fluoride-analyzer.rb
67
+ - spec/result-templater.rb
68
+ - spec/railtie_spec.rb
69
+ - spec/result-parser.rb
70
+ - spec-help/gem-test-suite.rb
71
+ homepage: http://github.com/lrdesign/fluoride-analyzer
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options:
77
+ - --inline-source
78
+ - --main
79
+ - doc/README
80
+ - --title
81
+ - fluoride-analyzer-0.0.1 Documentation
82
+ require_paths:
83
+ - lib/
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.0.14
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Analysis of recorded requests
100
+ test_files:
101
+ - spec-help/gem-test-suite.rb