fluoride-collector 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.
@@ -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