fluoride-collector 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 79df9f5613527c47e3bfc8d757c779c992e0e34b
4
+ data.tar.gz: d00870129d5e02049f0d502dffcf5e2ba06f11e2
5
+ SHA512:
6
+ metadata.gz: edcf5210f705bcf17fd40c5734a95537fe09877365761e6bfe68ccb159ceae23bbda5c949969fad19871418702695e648a3a38c22f2bd4e1ebcd36bb417923d0
7
+ data.tar.gz: 355afa02a28de428224911db463581798c9dec9d257e6ba91030056c3e8b7b07b55ec3ebfaebbb133acd3ba2d02a804f5c2e354b3ecb819ecd4c0533335b915a
@@ -0,0 +1,2 @@
1
+ require 'fluoride-collector/middleware'
2
+ require 'fluoride-collector/rails' if defined?(Rails)
@@ -0,0 +1,98 @@
1
+ module Fluoride
2
+ module Collector
3
+ class Middleware
4
+ def initialize(app, directory, tagging = nil)
5
+ @app = app
6
+ @directory = directory
7
+ @tagging = tagging
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env).tap do |response|
12
+ record_exchange(env, response)
13
+ end
14
+ rescue Object => ex
15
+ record_exception(env, ex)
16
+ raise
17
+ end
18
+
19
+ private
20
+
21
+ def record_exchange(env, response)
22
+ store(
23
+ "type" => "normal_exchange",
24
+ "tags" => @tagging,
25
+ "request" => request_hash(env),
26
+ "response" => response_hash(response)
27
+ )
28
+ end
29
+
30
+ def record_exception(env, ex)
31
+ store(
32
+ "type" => "exception_raised",
33
+ "tags" => @tagging,
34
+ "request" => request_hash(env),
35
+ "response" => exception_hash(ex)
36
+ )
37
+ end
38
+
39
+ def request_hash(env)
40
+ body = nil
41
+ if env['rack.input'].respond_to? :read
42
+ body = env['rack.input'].read
43
+ env['rack.input'].rewind rescue nil
44
+ end
45
+ {
46
+ "content_type" => env['CONTENT_TYPE'],
47
+ "accept" => env["HTTP_ACCEPT_ENCODING"],
48
+ "referer" => env["HTTP_REFERER"],
49
+ "cookies" => env["HTTP_COOKIE"],
50
+ "authorization" => env["HTTP_AUTHORIZATION"],
51
+ "method" => env["REQUEST_METHOD"],
52
+ "host" => env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}",
53
+ "path" => env["SCRIPT_NAME"].to_s + env["PATH_INFO"].to_s,
54
+ "query_string" => env["QUERY_STRING"].to_s,
55
+ "body" => body,
56
+ }
57
+ end
58
+
59
+ def response_hash(response)
60
+ status, headers, body = *response
61
+
62
+ {
63
+ "status" => status,
64
+ "headers" => headers,
65
+ "body" => body.to_a.join("") #every body? all of it?
66
+ }
67
+ end
68
+
69
+ def exception_hash(ex)
70
+ {
71
+ "type" => ex.class.name,
72
+ "message" => ex.message,
73
+ "backtrace" => ex.backtrace[0..10]
74
+ }
75
+ end
76
+
77
+ def thread_locals
78
+ Thread.current[:fluoride_collector] ||= {}
79
+ end
80
+
81
+ def storage_path
82
+ thread_locals[:storage_path] ||= File::join(@directory, "collection-#{Process.pid}-#{Thread.current.object_id}.yml")
83
+ end
84
+
85
+ def storage_file
86
+ File::open(storage_path, "a") do |file|
87
+ yield file
88
+ end
89
+ end
90
+
91
+ def store(record)
92
+ storage_file do |file|
93
+ file.write(YAML::dump(record))
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1 @@
1
+ require 'fluoride-collector/rails/railtie'
@@ -0,0 +1,14 @@
1
+ module Fluoride
2
+ module Collector
3
+ class Railtie < ::Rails::Railtie
4
+ config.fluoride = ActiveSupport::OrderedOptions.new
5
+ config.fluoride.tags = nil
6
+ config.fluoride.directory = "fluoride-collector"
7
+
8
+ initializer "fluoride-collector.add_middleware" do |app|
9
+ app.middleware.insert_after("ActionDispatch::ShowExceptions",
10
+ Fluoride::Collector::Middleware, config.fluoride.directory, config.fluoride.tags)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,118 @@
1
+ require 'rack'
2
+ require 'fluoride-collector'
3
+
4
+ describe Fluoride::Collector::Middleware do
5
+ include FileSandbox
6
+
7
+ let! :collection_directory do
8
+ dir = sandbox.new(:directory => "collections")
9
+ Dir.new(dir.path)
10
+ end
11
+
12
+ let :app do
13
+ run_app = test_app
14
+ Rack::Builder.app do
15
+ use Fluoride::Collector::Middleware, "collections", "TEST"
16
+ run run_app
17
+ end
18
+ end
19
+
20
+ let :env do
21
+ {}
22
+ end
23
+
24
+ describe "handling exception" do
25
+ let :test_ex_class do
26
+ Class.new(Exception)
27
+ end
28
+
29
+ let :test_app do
30
+ lambda{|env| raise test_ex_class, "test exception"}
31
+ end
32
+
33
+ it "should not change the response" do
34
+ expect{
35
+ app.call(env)
36
+ }.to raise_error
37
+ end
38
+
39
+ it "should create a collection file" do
40
+ expect do
41
+ begin
42
+ app.call(env)
43
+ rescue test_ex_class
44
+ end
45
+ end.to change{collection_directory.each.to_a.grep(/collection.*/).size}
46
+ end
47
+
48
+ it "should keep using the same collection file" do
49
+ begin
50
+ app.call(env)
51
+ rescue test_ex_class
52
+ end
53
+
54
+ expect do
55
+ begin
56
+ app.call(env)
57
+ rescue test_ex_class
58
+ end
59
+ path = File::join(collection_directory.path, collection_directory.each.to_a.grep(/collection.*/).first)
60
+ end.not_to change{collection_directory.each.to_a.grep(/collection.*/).size}
61
+ end
62
+
63
+ describe "creates a file" do
64
+ let :yaml do
65
+ begin
66
+ app.call(env)
67
+ rescue test_ex_class
68
+ end
69
+ path = File::join(collection_directory.path, collection_directory.each.to_a.grep(/collection.*/).first)
70
+ YAML.load_stream(File.read(path)).first
71
+ end
72
+
73
+ it "should have tags" do
74
+ yaml["tags"].should == "TEST"
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "handling successful responses" do
80
+ let :test_app do
81
+ lambda{|env| response }
82
+ end
83
+
84
+ let :response do
85
+ [200, {'Content-Type' => 'text/plain'}, ['Just a test']]
86
+ end
87
+
88
+ it "should not change the response" do
89
+ app.call(env).should == response
90
+ end
91
+
92
+ it "should create a collection file" do
93
+ expect do
94
+ app.call(env)
95
+ end.to change{collection_directory.each.to_a.grep(/collection.*/).size}
96
+ end
97
+
98
+ it "should keep using the same collection file" do
99
+ app.call(env)
100
+ expect do
101
+ app.call(env)
102
+ path = File::join(collection_directory.path, collection_directory.each.to_a.grep(/collection.*/).first)
103
+ end.not_to change{collection_directory.each.to_a.grep(/collection.*/).size}
104
+ end
105
+
106
+ describe "creates a file" do
107
+ let :yaml do
108
+ app.call(env)
109
+ path = File::join(collection_directory.path, collection_directory.each.to_a.grep(/collection.*/).first)
110
+ YAML.load_stream(File.read(path)).first
111
+ end
112
+
113
+ it "should have tags" do
114
+ yaml["tags"].should == "TEST"
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,10 @@
1
+ require 'railtie-help'
2
+
3
+ describe Fluoride::Collector::Railtie do
4
+ it "should update the middleware stack" do
5
+ #Ugh :(
6
+
7
+ Rails.application.middleware.middlewares.should include(Fluoride::Collector::Middleware)
8
+ end
9
+
10
+ end
@@ -0,0 +1,164 @@
1
+ #require 'ftools'
2
+ require 'fileutils'
3
+
4
+ module FileSandbox
5
+ def self.included(spec)
6
+ return unless spec.respond_to? :before
7
+
8
+ spec.before do
9
+ setup_sandbox
10
+ end
11
+
12
+ spec.after do
13
+ teardown_sandbox
14
+ end
15
+ end
16
+
17
+ class HaveContents
18
+ def initialize(contents)
19
+ @contents = contents
20
+ end
21
+
22
+ def matches?(target)
23
+ case @contents
24
+ when Regexp
25
+ @contents =~ target.contents
26
+ when String
27
+ @contents == target.contents
28
+ end
29
+ end
30
+ end
31
+
32
+ def have_contents(expected)
33
+ HaveContents.new(expected)
34
+ end
35
+
36
+ attr_reader :sandbox
37
+
38
+ def in_sandbox(&block)
39
+ raise "I expected to create a sandbox as you passed in a block to me" if !block_given?
40
+
41
+ setup_sandbox
42
+ original_error = nil
43
+
44
+ begin
45
+ yield @sandbox
46
+ rescue => e
47
+ original_error = e
48
+ raise
49
+ ensure
50
+ begin
51
+ teardown_sandbox
52
+ rescue
53
+ if original_error
54
+ STDERR.puts "ALERT: a test raised an error and failed to release some lock(s) in the sandbox directory"
55
+ raise(original_error)
56
+ else
57
+ raise
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def setup_sandbox(path = '__sandbox')
64
+ unless @sandbox
65
+ @sandbox = Sandbox.new(path)
66
+ @__old_path_for_sandbox = Dir.pwd
67
+ Dir.chdir(@sandbox.root)
68
+ end
69
+ end
70
+
71
+ def teardown_sandbox
72
+ if @sandbox
73
+ Dir.chdir(@__old_path_for_sandbox)
74
+ @sandbox.clean_up
75
+ @sandbox = nil
76
+ end
77
+ end
78
+
79
+ class Sandbox
80
+ attr_reader :root
81
+
82
+ def initialize(path = '__sandbox')
83
+ @root = File.expand_path(path)
84
+ clean_up
85
+ FileUtils.mkdir_p @root
86
+ end
87
+
88
+ def [](name)
89
+ SandboxFile.new(File.join(@root, name), name)
90
+ end
91
+
92
+ # usage new :file=>'my file.rb', :with_contents=>'some stuff'
93
+ def new(options)
94
+ if options.has_key? :directory
95
+ dir = self[options.delete(:directory)]
96
+ FileUtils.mkdir_p dir.path
97
+ else
98
+ file = self[options.delete(:file)]
99
+ if (binary_content = options.delete(:with_binary_content) || options.delete(:with_binary_contents))
100
+ file.binary_content = binary_content
101
+ else
102
+ file.content = (options.delete(:with_content) || options.delete(:with_contents) || '')
103
+ end
104
+ end
105
+
106
+ raise "unexpected keys '#{options.keys.join(', ')}'" unless options.empty?
107
+
108
+ dir || file
109
+ end
110
+
111
+ def remove(options)
112
+ name = File.join(@root, options[:file])
113
+ FileUtils.remove_file name
114
+ end
115
+
116
+ def clean_up
117
+ FileUtils.rm_rf @root
118
+ if File.exists? @root
119
+ raise "Could not remove directory #{@root.inspect}, something is probably still holding a lock on it"
120
+ end
121
+ end
122
+ end
123
+
124
+
125
+ class SandboxFile
126
+ attr_reader :path
127
+
128
+ def initialize(path, sandbox_path)
129
+ @path = path
130
+ @sandbox_path = sandbox_path
131
+ end
132
+
133
+ def inspect
134
+ "SandboxFile: #@sandbox_path"
135
+ end
136
+
137
+ def exist?
138
+ File.exist? path
139
+ end
140
+
141
+ def content
142
+ File.read path
143
+ end
144
+
145
+ def content=(content)
146
+ FileUtils.mkdir_p File.dirname(@path)
147
+ File.open(@path, "w") {|f| f << content}
148
+ end
149
+
150
+ def binary_content=(content)
151
+ FileUtils.mkdir_p File.dirname(@path)
152
+ File.open(@path, "wb") {|f| f << content}
153
+ end
154
+
155
+ def create
156
+ self.content = ''
157
+ end
158
+
159
+ alias exists? exist?
160
+ alias contents content
161
+ alias contents= content=
162
+ alias binary_contents= binary_content=
163
+ end
164
+ 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,24 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ # Only the parts of rails we want to use
4
+ # if you want everything, use "rails/all"
5
+ require "action_controller/railtie"
6
+ require "rails/test_unit/railtie"
7
+ require 'fluoride-collector/rails'
8
+
9
+ #root = File.expand_path(File.dirname(__FILE__))
10
+
11
+ # Define the application and configuration
12
+ module Fixture
13
+ class Application < ::Rails::Application
14
+ # configuration here if needed
15
+ config.active_support.deprecation = :stderr
16
+ config.eager_load = false
17
+ end
18
+ end
19
+
20
+ # Initialize the application
21
+ Fixture::Application.initialize!
22
+
23
+ RSpec.configure do |config|
24
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'rspec/core/formatters/base_formatter'
3
+ require 'cadre/rspec'
4
+ require 'file-sandbox'
5
+
6
+ RSpec.configure do |config|
7
+ config.run_all_when_everything_filtered = true
8
+ config.add_formatter(Cadre::RSpec::NotifyOnCompleteFormatter)
9
+ config.add_formatter(Cadre::RSpec::QuickfixFormatter)
10
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluoride-collector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Judson Lester
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |2
14
+ Part of the Fluoride suite - tools for making your black box a bit whiter
15
+ email:
16
+ - nyarly@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/fluoride-collector/rails/railtie.rb
22
+ - lib/fluoride-collector/rails.rb
23
+ - lib/fluoride-collector/middleware.rb
24
+ - lib/fluoride-collector.rb
25
+ - spec/railtie.rb
26
+ - spec/middleware.rb
27
+ - spec_help/spec_helper.rb
28
+ - spec_help/gem_test_suite.rb
29
+ - spec_help/railtie-help.rb
30
+ - spec_help/file-sandbox.rb
31
+ homepage: http://nyarly.github.com/fluoride-collector
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --inline-source
38
+ - --main
39
+ - doc/README
40
+ - --title
41
+ - fluoride-collector-0.0.1 Documentation
42
+ require_paths:
43
+ - lib/
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project: fluoride-collector
56
+ rubygems_version: 2.0.14
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Middleware to collect request and reponse pairs
60
+ test_files:
61
+ - spec_help/gem_test_suite.rb