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.
- checksums.yaml +7 -0
- data/lib/fluoride-collector.rb +2 -0
- data/lib/fluoride-collector/middleware.rb +98 -0
- data/lib/fluoride-collector/rails.rb +1 -0
- data/lib/fluoride-collector/rails/railtie.rb +14 -0
- data/spec/middleware.rb +118 -0
- data/spec/railtie.rb +10 -0
- data/spec_help/file-sandbox.rb +164 -0
- data/spec_help/gem_test_suite.rb +17 -0
- data/spec_help/railtie-help.rb +24 -0
- data/spec_help/spec_helper.rb +10 -0
- metadata +61 -0
checksums.yaml
ADDED
@@ -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,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
|
data/spec/middleware.rb
ADDED
@@ -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
|
data/spec/railtie.rb
ADDED
@@ -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
|