fluoride-analyzer 0.0.1

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.
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