hyphy 0.0.0 → 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.
@@ -1,31 +1,43 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Hyphy::DurationFilter do
3
+ describe Hyphy::Filters::DurationFilter do
4
4
 
5
- let!(:sql_statement1) { Hyphy::SQLStatement.create(:statement => 'select count(*) from table1',
6
- :start_time => 1.0,
7
- :end_time => 1.1) }
5
+ before(:each) do
6
+ @sql_statement1 = Hyphy::SQLStatement.new(:statement => 'select count(*) from table1',
7
+ :start_time => 1.0,
8
+ :end_time => 1.1)
8
9
 
9
- let!(:sql_statement2) { Hyphy::SQLStatement.create(:statement => 'select count(*) from table2',
10
- :start_time => 2.0,
11
- :end_time => 2.1) }
10
+ @sql_statement2 = Hyphy::SQLStatement.new(:statement => 'select count(*) from table2',
11
+ :start_time => 2.0,
12
+ :end_time => 2.1)
12
13
 
13
- let!(:sql_statement3) { Hyphy::SQLStatement.create(:statement => 'select count(*) from table3',
14
- :start_time => 2.0,
15
- :end_time => 3.0) }
14
+ @sql_statement3 = Hyphy::SQLStatement.new(:statement => 'select count(*) from table3',
15
+ :start_time => 2.0,
16
+ :end_time => 3.0)
16
17
 
17
- let!(:sql_statement4) { Hyphy::SQLStatement.create(:statement => 'select count(*) from table4',
18
- :start_time => 3.0,
19
- :end_time => 10.0) }
18
+ @sql_statement4 = Hyphy::SQLStatement.new(:statement => 'select count(*) from table4',
19
+ :start_time => 3.0,
20
+ :end_time => 10.0)
21
+ @sql_statement4.benchmark_time = 7
20
22
 
21
- let(:dataset) { Hyphy::Dataset.new }
23
+ @sampler = Hyphy::Sampler.new
24
+ @sampler.dataset = [@sql_statement1, @sql_statement2, @sql_statement3, @sql_statement4]
25
+ end
22
26
 
23
27
  describe "#filter" do
24
28
 
25
29
  it 'only returns the sql statements that last longer than one second' do
26
- dataset.apply_filter(Hyphy::DurationFilter, :duration_min => 1.0)
30
+ @sampler.apply_filter(Hyphy::Filters::DurationFilter, :duration_min => 1.0)
31
+
32
+ @sampler.dataset.should == [@sql_statement4, @sql_statement3]
33
+ end
34
+
35
+ it 'returns the sql statements that have a benchmark time longer than one second' do
36
+ @sampler.apply_filter(Hyphy::Filters::DurationFilter,
37
+ :benchmark => true,
38
+ :duration_min => 1.0)
27
39
 
28
- dataset.data.should == [sql_statement4, sql_statement3]
40
+ @sampler.dataset.should == [@sql_statement4]
29
41
  end
30
42
 
31
43
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hyphy::Filters::LimitFilter do
4
+
5
+ before(:each) do
6
+ @limit = 3
7
+ @data = [0, 1, 2, 3]
8
+ end
9
+
10
+ describe "#filter" do
11
+
12
+ it 'strips the data to a length of the specified limit' do
13
+ limit_filter = Hyphy::Filters::LimitFilter.new(@data, :limit => @limit)
14
+ limit_filter.filter
15
+
16
+ limit_filter.data.should == [0, 1, 2]
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hyphy::Filters::SQLFilter do
4
+
5
+ before(:each) do
6
+ @sql_statement1 = Hyphy::SQLStatement.new(:statement => "select * from table")
7
+ @sql_statement2 = Hyphy::SQLStatement.new(:statement => "insert into table values 1, 2, 3")
8
+ @data = [@sql_statement1, @sql_statement2]
9
+ end
10
+
11
+ describe "#initialize" do
12
+
13
+ it "throws an exception when an incorrect SQL statement type is provided" do
14
+ expect { Hyphy::Filters::SQLFilter.new(@data, :type => :lol) }
15
+ .to raise_error(Hyphy::Filters::SQLFilter::IncorrectSQLTypeException)
16
+ end
17
+
18
+ end
19
+
20
+ describe "#filter" do
21
+
22
+ it "filters the data to include SQL statements of the right type" do
23
+ sql_filter = Hyphy::Filters::SQLFilter.new(@data, :type => :select)
24
+ sql_filter.filter
25
+
26
+ @data.should == [@sql_statement1]
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -1,5 +1,3 @@
1
- require 'json'
2
-
3
1
  require "spec_helper"
4
2
 
5
3
  describe Hyphy::SQLStatement do
@@ -8,8 +6,8 @@ describe Hyphy::SQLStatement do
8
6
  let(:sql_statement) { Hyphy::SQLStatement.new(:statement => statement,
9
7
  :start_time => 2,
10
8
  :end_time => 3.001,
11
- :trace_json => JSON(["hello!"]),
12
- :metadata_json => JSON({ "hello!" => "hi!" })) }
9
+ :trace => ["hello!"],
10
+ :metadata => { "hello!" => "hi!" }) }
13
11
 
14
12
  describe "#duration" do
15
13
 
@@ -48,14 +46,13 @@ describe Hyphy::SQLStatement do
48
46
 
49
47
  end
50
48
 
51
- describe ".truncate_table" do
49
+ describe "#application_trace" do
52
50
 
53
- it 'should clear all sql_statements rows' do
54
- Hyphy::SQLStatement.create
55
- Hyphy::SQLStatement.all.count.should == 1
51
+ it "returns the trace lines that are related to the running application" do
52
+ sql_statement.stub(:trace).and_return(['/1', '/2', '/3'])
53
+ Dir.stub(:pwd).and_return('/1')
56
54
 
57
- Hyphy::SQLStatement.truncate_table
58
- Hyphy::SQLStatement.all.count.should == 0
55
+ sql_statement.application_trace.should == ['/1']
59
56
  end
60
57
 
61
58
  end
@@ -71,11 +68,36 @@ describe Hyphy::SQLStatement do
71
68
  describe "#add_metadata" do
72
69
 
73
70
  it "should store the key, value pair in the metadata" do
74
- sql_statement.add_metadata("key", "value")
71
+ sql_statement.metadata["key"] = "value"
75
72
 
76
73
  sql_statement.metadata["key"].should == "value"
77
74
  end
78
75
 
79
76
  end
80
77
 
78
+ describe "statement methods" do
79
+
80
+ let(:sql_statement1) { Hyphy::SQLStatement.new(:statement => "select * from table") }
81
+ let(:sql_statement2) { Hyphy::SQLStatement.new(:statement => "insert into table values 1, 2, 3") }
82
+
83
+ describe "#select?" do
84
+
85
+ it "is true for a select statement" do
86
+ sql_statement1.select?.should be_true
87
+ sql_statement2.select?.should be_false
88
+ end
89
+
90
+ end
91
+
92
+ describe "#insert?" do
93
+
94
+ it "is true for a insert statement" do
95
+ sql_statement1.insert?.should be_false
96
+ sql_statement2.insert?.should be_true
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
81
103
  end
@@ -3,6 +3,7 @@ require "spec_helper"
3
3
  describe Hyphy::ActiveRecordAdapter do
4
4
 
5
5
  let(:sql_statement) { 'select count(*) from victims' }
6
+ let(:sampler) { Hyphy::Sampler.new }
6
7
  let(:start_time) { 1.0001 }
7
8
  let(:end_time) { 1.0002 }
8
9
 
@@ -10,13 +11,44 @@ describe Hyphy::ActiveRecordAdapter do
10
11
 
11
12
  it "should catch sql.active_record notifications" do
12
13
  ActiveSupport::Notifications.should_receive(:subscribe)
13
- .and_yield(nil, start_time, end_time, nil, { :sql => sql_statement })
14
+ .and_yield(nil,
15
+ start_time,
16
+ end_time,
17
+ nil, { :sql => sql_statement,
18
+ :binds => [] })
14
19
 
15
- callback = lambda { |a, b, c| }
20
+ callback = sampler.method(:sample)
16
21
 
17
22
  Hyphy::ActiveRecordAdapter.subscribe_to_sql_notifications(callback)
18
23
  end
19
24
 
20
25
  end
21
26
 
27
+ describe ".unsubscribe_to_sql_notifications" do
28
+
29
+ it "unsubscribes subscriber notifications from ActiveSupport"do
30
+ subscriber = double()
31
+ ActiveSupport::Notifications.should_receive(:unsubscribe)
32
+ .with(subscriber)
33
+
34
+ Hyphy::ActiveRecordAdapter.unsubscribe_to_sql_notifications(subscriber)
35
+ end
36
+
37
+ end
38
+
39
+ describe ".time_statement" do
40
+
41
+ it "Returns a float time value that represents the duration of a statement" do
42
+ ActiveRecord::Base.stub_chain(:connection, :clear_query_cache)
43
+
44
+ Benchmark.stub(:realtime).and_return(3.0)
45
+ Marshal.stub(:load).and_return([])
46
+ sql_statement = Hyphy::SQLStatement.new(:statement => 'select * from table')
47
+
48
+ Hyphy::ActiveRecordAdapter.time_statement(sql_statement)
49
+ .should == 3.0
50
+ end
51
+
52
+ end
53
+
22
54
  end
data/spec/sampler_spec.rb CHANGED
@@ -30,13 +30,15 @@ describe Hyphy::Sampler do
30
30
  it 'creates a new SQLStatement row' do
31
31
  sampler.log_sql(statement,
32
32
  start_time,
33
- end_time)
33
+ end_time,
34
+ Hyphy::ActiveRecordAdapter)
34
35
 
35
- sql_statement = Hyphy::SQLStatement.last
36
+ sql_statement = sampler.dataset.last
36
37
  sql_statement.statement.should == statement
37
38
  sql_statement.start_time.should == start_time
38
39
  sql_statement.end_time.should == end_time
39
40
  sql_statement.trace.class.should == Array
41
+ sql_statement.orm_adapter.should == Hyphy::ActiveRecordAdapter
40
42
  end
41
43
 
42
44
  end
@@ -44,7 +46,11 @@ describe Hyphy::Sampler do
44
46
  describe "#sample" do
45
47
 
46
48
  it "logs the SQL statement and adds metadata" do
47
- sampler.should_receive(:log_sql).with(statement, start_time, end_time)
49
+ sampler.should_receive(:log_sql).with(statement,
50
+ start_time,
51
+ end_time,
52
+ Hyphy::ActiveRecordAdapter)
53
+
48
54
  sampler.should_receive(:process_metadata)
49
55
 
50
56
  sampler.sample(statement, start_time, end_time)
@@ -64,7 +70,7 @@ describe Hyphy::Sampler do
64
70
 
65
71
  describe "#process_metadata" do
66
72
 
67
- let(:sql_statement) { Hyphy::SQLStatement.create }
73
+ let(:sql_statement) { Hyphy::SQLStatement.new }
68
74
 
69
75
  it "adds metadata from a proc to a SQLStatement" do
70
76
  sampler.add_metadata("test") { "this is just a test!" }
@@ -75,4 +81,49 @@ describe Hyphy::Sampler do
75
81
 
76
82
  end
77
83
 
84
+ describe "#stop" do
85
+
86
+ it 'unsubscribes SQL notifications' do
87
+ subscriber = sampler.begin
88
+ Hyphy::ActiveRecordAdapter.should_receive(:unsubscribe_to_sql_notifications)
89
+ .with(subscriber)
90
+
91
+ sampler.stop
92
+ end
93
+
94
+ end
95
+
96
+ describe "#apply_filter" do
97
+
98
+ before(:each) do
99
+ @sampler = Hyphy::Sampler.new
100
+ @sql_statement1 = Hyphy::SQLStatement.new(:statement => "select * from table1",
101
+ :start_time => 1.001,
102
+ :end_time => 2.002)
103
+
104
+ @sql_statement2 = Hyphy::SQLStatement.new(:statement => "select * from table2",
105
+ :start_time => 1.001,
106
+ :end_time => 3.002)
107
+
108
+ @sampler.dataset << @sql_statement1
109
+ @sampler.dataset << @sql_statement2
110
+ end
111
+
112
+ it "filters the in memory dataset" do
113
+ @sampler.apply_filter(Hyphy::Filters::DurationFilter, :duration_min => 1.5)
114
+ @sampler.dataset.should == [@sql_statement2]
115
+ end
116
+
117
+ end
118
+
119
+ describe "#profile" do
120
+
121
+ it "starts and stops the sampling"do
122
+ sampler.should_receive(:begin)
123
+ sampler.should_receive(:stop)
124
+ sampler.profile {}
125
+ end
126
+
127
+ end
128
+
78
129
  end
data/spec/spec_helper.rb CHANGED
@@ -3,7 +3,6 @@ SimpleCov.start
3
3
 
4
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
- require 'database_cleaner'
7
6
  require 'pry-nav'
8
7
  require 'rspec'
9
8
  require 'hyphy'
@@ -15,15 +14,12 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
15
14
  RSpec.configure do |config|
16
15
 
17
16
  config.before(:suite) do
18
- DatabaseCleaner.strategy = :transaction
19
17
  end
20
18
 
21
19
  config.before(:each) do
22
- DatabaseCleaner.start
23
20
  end
24
21
 
25
22
  config.after(:each) do
26
- DatabaseCleaner.clean
27
23
  end
28
24
 
29
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyphy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,42 +9,26 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-24 00:00:00.000000000 Z
12
+ date: 2013-07-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: sequel
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
- - !ruby/object:Gem::Dependency
31
- name: sqlite3
15
+ name: activesupport
32
16
  requirement: !ruby/object:Gem::Requirement
33
17
  none: false
34
18
  requirements:
35
- - - ! '>='
19
+ - - ~>
36
20
  - !ruby/object:Gem::Version
37
- version: '0'
21
+ version: '3.2'
38
22
  type: :runtime
39
23
  prerelease: false
40
24
  version_requirements: !ruby/object:Gem::Requirement
41
25
  none: false
42
26
  requirements:
43
- - - ! '>='
27
+ - - ~>
44
28
  - !ruby/object:Gem::Version
45
- version: '0'
29
+ version: '3.2'
46
30
  - !ruby/object:Gem::Dependency
47
- name: activesupport
31
+ name: activerecord
48
32
  requirement: !ruby/object:Gem::Requirement
49
33
  none: false
50
34
  requirements:
@@ -75,22 +59,6 @@ dependencies:
75
59
  - - ! '>='
76
60
  - !ruby/object:Gem::Version
77
61
  version: '0'
78
- - !ruby/object:Gem::Dependency
79
- name: database_cleaner
80
- requirement: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
83
- - - ! '>='
84
- - !ruby/object:Gem::Version
85
- version: '0'
86
- type: :development
87
- prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
- requirements:
91
- - - ! '>='
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
62
  - !ruby/object:Gem::Dependency
95
63
  name: jeweler
96
64
  requirement: !ruby/object:Gem::Requirement
@@ -171,7 +139,12 @@ dependencies:
171
139
  - - ! '>='
172
140
  - !ruby/object:Gem::Version
173
141
  version: '0'
174
- description: Identify SQL bottlenecks in tests
142
+ description: ! 'Hyphy is a toolkit for identifying SQL bottlenecks in Ruby applications.
143
+ Given
144
+
145
+ an adapter for an ORM and a Ruby block, Hyphy collects all executed queries in
146
+
147
+ a dataset. Afterward, it can filter the dataset and even benchmark the queries.'
175
148
  email: david@nationbuilder.com
176
149
  executables: []
177
150
  extensions: []
@@ -179,7 +152,6 @@ extra_rdoc_files:
179
152
  - LICENSE.txt
180
153
  - README.md
181
154
  files:
182
- - .document
183
155
  - .rspec
184
156
  - .ruby-gemset
185
157
  - .ruby-version
@@ -191,24 +163,24 @@ files:
191
163
  - VERSION
192
164
  - hyphy.gemspec
193
165
  - lib/hyphy.rb
194
- - lib/hyphy/database.rb
195
- - lib/hyphy/dataset.rb
196
- - lib/hyphy/dataset_collection.rb
197
166
  - lib/hyphy/filters/abstract_filter.rb
167
+ - lib/hyphy/filters/benchmark_filter.rb
198
168
  - lib/hyphy/filters/duration_filter.rb
199
- - lib/hyphy/models/sql_statement.rb
169
+ - lib/hyphy/filters/limit_filter.rb
170
+ - lib/hyphy/filters/sql_filter.rb
200
171
  - lib/hyphy/orm_adapters/abstract_orm_adapter.rb
201
172
  - lib/hyphy/orm_adapters/activerecord_adapter.rb
202
173
  - lib/hyphy/sampler.rb
203
- - spec/dataset_collection_spec.rb
204
- - spec/dataset_spec.rb
174
+ - lib/hyphy/sql_statement.rb
205
175
  - spec/filters/abstract_filter_spec.rb
176
+ - spec/filters/benchmark_filter_spec.rb
206
177
  - spec/filters/duration_filter_spec.rb
178
+ - spec/filters/limit_filter_spec.rb
179
+ - spec/filters/sql_filter_spec.rb
207
180
  - spec/models/sql_statement_spec.rb
208
181
  - spec/orm_adapters/activerecord_orm_adapter_spec.rb
209
182
  - spec/sampler_spec.rb
210
183
  - spec/spec_helper.rb
211
- - specification.txt
212
184
  homepage: http://github.com/3dna/hyphy
213
185
  licenses:
214
186
  - MIT
@@ -224,7 +196,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
196
  version: '0'
225
197
  segments:
226
198
  - 0
227
- hash: -1377831420524407634
199
+ hash: -2790169902531096751
228
200
  required_rubygems_version: !ruby/object:Gem::Requirement
229
201
  none: false
230
202
  requirements:
@@ -236,5 +208,5 @@ rubyforge_project:
236
208
  rubygems_version: 1.8.25
237
209
  signing_key:
238
210
  specification_version: 3
239
- summary: Identify SQL bottlenecks in tests
211
+ summary: A SQL bottleneck toolkit
240
212
  test_files: []
data/.document DELETED
@@ -1,5 +0,0 @@
1
- lib/**/*.rb
2
- bin/*
3
- -
4
- features/**/*.feature
5
- LICENSE.txt
@@ -1,3 +0,0 @@
1
- require 'sequel'
2
-
3
- Hyphy::DB = Sequel.sqlite
data/lib/hyphy/dataset.rb DELETED
@@ -1,14 +0,0 @@
1
- class Hyphy::Dataset
2
-
3
- attr_reader :data
4
-
5
- def initialize(data=nil)
6
- @data = data || Hyphy::SQLStatement.all
7
- end
8
-
9
- def apply_filter(filter_class, opts={})
10
- filter = filter_class.new(@data, opts)
11
- filter.filter
12
- end
13
-
14
- end
@@ -1,35 +0,0 @@
1
- class Hyphy::DatasetCollection
2
-
3
- class InvalidKeyException < Exception; end
4
-
5
- attr_reader :dataset_collection
6
-
7
- def initialize(dataset, key)
8
- raise InvalidKeyException unless Hyphy::SQLStatement.method_defined?(key)
9
-
10
- @key = key
11
- @dataset = dataset
12
- @dataset_collection = {}
13
- end
14
-
15
- def process_dataset
16
- collection = Hash.new { |hash, key| hash[key] = [] }
17
-
18
- @dataset.data.each do |sql_statement|
19
- collection[sql_statement.send(@key)] << sql_statement
20
- end
21
-
22
- collection.each { |key, value| @dataset_collection[key] = Hyphy::Dataset.new(value) }
23
- end
24
-
25
- def counts_hash
26
- key_to_count = {}
27
-
28
- @dataset_collection.map do |key, dataset|
29
- key_to_count[key] = dataset.data.count
30
- end
31
-
32
- key_to_count
33
- end
34
-
35
- end
@@ -1,49 +0,0 @@
1
- require 'json'
2
-
3
- Hyphy::DB.create_table(:sql_statements) do
4
- primary_key :id
5
-
6
- String :statement, :text => true
7
- String :trace_json, :text => true
8
- String :metadata_json, :text => true
9
- Float :start_time
10
- Float :end_time
11
- end
12
-
13
- class Hyphy::SQLStatement < Sequel::Model
14
-
15
- DIGIT_MARKER = '<digit>'
16
-
17
- def duration
18
- @duration ||= (end_time - start_time)
19
- end
20
-
21
- def stripped_statement
22
- statement.strip
23
- end
24
-
25
- def digitless
26
- without_digits = stripped_statement.gsub(/\d+/, DIGIT_MARKER)
27
- end
28
-
29
- def trace
30
- JSON.parse(trace_json)
31
- end
32
-
33
- def metadata
34
- return {} unless metadata_json
35
- JSON.parse(metadata_json)
36
- end
37
-
38
- def add_metadata(key, value)
39
- new_metadata = metadata
40
- new_metadata[key] = value
41
- self.metadata_json = JSON(new_metadata)
42
- save
43
- end
44
-
45
- def self.truncate_table
46
- Hyphy::DB[:sql_statements].truncate
47
- end
48
-
49
- end
@@ -1,38 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Hyphy::DatasetCollection do
4
-
5
- before(:each) do
6
- Hyphy::SQLStatement.create :statement => 'select * from table where id = 4'
7
- Hyphy::SQLStatement.create :statement => 'select * from table where id = 7'
8
- Hyphy::SQLStatement.create :statement => 'select * from table'
9
- end
10
-
11
- let(:dataset) { Hyphy::Dataset.new }
12
- let(:dataset_collection) { Hyphy::DatasetCollection.new(dataset, :statement) }
13
-
14
- describe "#process_dataset" do
15
-
16
- before(:each) { dataset_collection.process_dataset }
17
-
18
- it "creates a collection with each statement having a unique key" do
19
- dataset_collection.dataset_collection.keys.uniq.count.should == 3
20
- dataset_collection.dataset_collection.values.uniq.count.should == 3
21
- end
22
-
23
- end
24
-
25
- describe "#counts_hash" do
26
-
27
- before(:each) { dataset_collection.process_dataset }
28
-
29
- it "maps the correct statements to counts" do
30
- puts dataset_collection.counts_hash.should ==
31
- { "select * from table where id = 4" => 1,
32
- "select * from table where id = 7" => 1,
33
- "select * from table" => 1 }
34
- end
35
-
36
- end
37
-
38
- end