appstats 0.19.1 → 0.19.2
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.
- data/Gemfile.lock +1 -1
- data/lib/appstats/query.rb +22 -4
- data/lib/appstats/sub_result.rb +6 -0
- data/lib/appstats/version.rb +1 -1
- data/spec/entry_spec.rb +8 -8
- data/spec/logger_spec.rb +22 -22
- data/spec/query_spec.rb +690 -661
- data/spec/sub_result_spec.rb +19 -0
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/lib/appstats/query.rb
CHANGED
@@ -55,25 +55,43 @@ module Appstats
|
|
55
55
|
result.save
|
56
56
|
|
57
57
|
unless @group_by.empty?
|
58
|
+
running_total = 0
|
58
59
|
data = run_query { |conn| conn.select_all(@group_query_to_sql) }
|
59
60
|
result.group_query_duration_in_seconds = data[:duration] unless data.nil?
|
60
61
|
all_sub_results = data.nil? ? [] : data[:results]
|
61
62
|
all_sub_results.each do |data|
|
62
|
-
if data["context_key_filter"].nil? || data["
|
63
|
-
Appstats.log(:error,"Missing context_key_filter,
|
63
|
+
if data["context_key_filter"].nil? || data["num"].nil?
|
64
|
+
Appstats.log(:error,"Missing context_key_filter, or num in #{data.inspect}")
|
64
65
|
next
|
65
66
|
end
|
67
|
+
|
68
|
+
if data["context_value_filter"].nil?
|
69
|
+
Appstats.log(:error,"Missing context_value_filter, setting to empty string ''")
|
70
|
+
data["context_value_filter"] = ""
|
71
|
+
end
|
66
72
|
|
67
73
|
keys = data["context_key_filter"].split(",")
|
68
74
|
values = data["context_value_filter"].split(",")
|
69
75
|
key_values = {} and keys.each_with_index { |k,i| key_values[k] = values[i] }
|
70
|
-
|
71
|
-
|
76
|
+
current_count = data["num"].to_i
|
77
|
+
ratio_of_total = current_count.to_f / result.count
|
78
|
+
running_total += current_count
|
79
|
+
sub_result = Appstats::SubResult.new(:context_filter => @group_by.collect { |k| key_values[k] }.join(", "), :count => current_count, :ratio_of_total => ratio_of_total)
|
80
|
+
sub_result.result = result
|
81
|
+
sub_result.save
|
82
|
+
end
|
83
|
+
|
84
|
+
if running_total < result.count
|
85
|
+
remaining_total = result.count - running_total
|
86
|
+
ratio_of_total = remaining_total.to_f / result.count
|
87
|
+
sub_result = Appstats::SubResult.new(:context_filter => nil, :count => remaining_total, :ratio_of_total => ratio_of_total)
|
72
88
|
sub_result.result = result
|
73
89
|
sub_result.save
|
74
90
|
end
|
91
|
+
|
75
92
|
result.save
|
76
93
|
end
|
94
|
+
|
77
95
|
result.reload
|
78
96
|
result
|
79
97
|
end
|
data/lib/appstats/sub_result.rb
CHANGED
@@ -17,6 +17,12 @@ module Appstats
|
|
17
17
|
def total_count_to_s(data = {})
|
18
18
|
Appstats::Result.calculate_count_to_s(total_count,data)
|
19
19
|
end
|
20
|
+
|
21
|
+
def context_filter_to_s
|
22
|
+
return "-- N/A --" if context_filter.nil?
|
23
|
+
return "-- No Value --" if context_filter.empty?
|
24
|
+
context_filter
|
25
|
+
end
|
20
26
|
|
21
27
|
|
22
28
|
def ==(o)
|
data/lib/appstats/version.rb
CHANGED
data/spec/entry_spec.rb
CHANGED
@@ -193,18 +193,18 @@ module Appstats
|
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should understand an entry without contexts" do
|
196
|
-
entry = Entry.create_from_logger_string("0.19.
|
196
|
+
entry = Entry.create_from_logger_string("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
|
197
197
|
Entry.count.should == @before_count + 1
|
198
198
|
entry.action.should == "address_search"
|
199
|
-
entry.raw_entry.should == "0.19.
|
199
|
+
entry.raw_entry.should == "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
|
200
200
|
entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
|
201
201
|
end
|
202
202
|
|
203
203
|
it "should understand contexts" do
|
204
|
-
entry = Entry.create_from_logger_string("0.19.
|
204
|
+
entry = Entry.create_from_logger_string("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
|
205
205
|
Entry.count.should == @before_count + 1
|
206
206
|
entry.action.should == "address_filter"
|
207
|
-
entry.raw_entry.should == "0.19.
|
207
|
+
entry.raw_entry.should == "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
|
208
208
|
entry.occurred_at.should == Time.parse("2010-09-21 23:15:20")
|
209
209
|
entry.contexts.size.should == 2
|
210
210
|
entry.contexts[0].context_key = "app_name"
|
@@ -214,10 +214,10 @@ module Appstats
|
|
214
214
|
end
|
215
215
|
|
216
216
|
it "should handle 'action' as a context" do
|
217
|
-
entry = Entry.create_from_logger_string('0.19.
|
217
|
+
entry = Entry.create_from_logger_string('0.19.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb')
|
218
218
|
Entry.count.should == @before_count + 1
|
219
219
|
entry.action.should == "page-view"
|
220
|
-
entry.raw_entry.should == "0.19.
|
220
|
+
entry.raw_entry.should == "0.19.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : action=save_ovcen : app_name=cdb"
|
221
221
|
entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
|
222
222
|
entry.contexts.size.should == 2
|
223
223
|
entry.contexts[0].context_key = "action"
|
@@ -228,10 +228,10 @@ module Appstats
|
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should handle multiple of the same 'context'" do
|
231
|
-
entry = Entry.create_from_logger_string('0.19.
|
231
|
+
entry = Entry.create_from_logger_string('0.19.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb')
|
232
232
|
Entry.count.should == @before_count + 1
|
233
233
|
entry.action.should == "page-view"
|
234
|
-
entry.raw_entry.should == "0.19.
|
234
|
+
entry.raw_entry.should == "0.19.2 setup[:,=,-n] 2011-02-24 12:59:57 action=page-view : app_name=market : app_name=cdb"
|
235
235
|
entry.occurred_at.should == Time.parse("2011-02-24 12:59:57")
|
236
236
|
entry.contexts.size.should == 2
|
237
237
|
entry.contexts[0].context_key = "app_name"
|
data/spec/logger_spec.rb
CHANGED
@@ -122,12 +122,12 @@ module Appstats
|
|
122
122
|
|
123
123
|
it "should accept numbers" do
|
124
124
|
Appstats::Logger.entry(5, :blah => 6)
|
125
|
-
Appstats::Logger.raw_read.should == ["0.19.
|
125
|
+
Appstats::Logger.raw_read.should == ["0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=5 : blah=6"]
|
126
126
|
end
|
127
127
|
|
128
128
|
it "should accept arrays" do
|
129
129
|
Appstats::Logger.entry('search', :provider => [ 'one', 'two' ])
|
130
|
-
Appstats::Logger.raw_read.should == ["0.19.
|
130
|
+
Appstats::Logger.raw_read.should == ["0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=search : provider=one : provider=two"]
|
131
131
|
end
|
132
132
|
|
133
133
|
|
@@ -137,7 +137,7 @@ module Appstats
|
|
137
137
|
|
138
138
|
it "should look similar to regular entry" do
|
139
139
|
Appstats::Logger.exception_entry(RuntimeError.new("blah"),:on => "login")
|
140
|
-
Appstats::Logger.raw_read.should == ["0.19.
|
140
|
+
Appstats::Logger.raw_read.should == ["0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=appstats-exception : error=blah : on=login"]
|
141
141
|
end
|
142
142
|
|
143
143
|
end
|
@@ -154,47 +154,47 @@ module Appstats
|
|
154
154
|
|
155
155
|
it "should handle a statistics entry" do
|
156
156
|
expected = { :action => "address_search", :timestamp => "2010-09-21 23:15:20" }
|
157
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
157
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search")
|
158
158
|
actual.should == expected
|
159
159
|
end
|
160
160
|
|
161
161
|
it "should handle contexts" do
|
162
162
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
163
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
163
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live")
|
164
164
|
actual.should == expected
|
165
165
|
end
|
166
166
|
|
167
167
|
it "should handle multiple actions" do
|
168
168
|
expected = { :action => ["address_filter", "blah"], :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
169
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
169
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : action=blah : app_name=Market : server=Live")
|
170
170
|
actual.should == expected
|
171
171
|
end
|
172
172
|
|
173
173
|
it "should handle multiple of same context" do
|
174
174
|
expected = { :action => "address_filter", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => ['Sin','Market'] }
|
175
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
175
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Sin : app_name=Market : server=Live")
|
176
176
|
actual.should == expected
|
177
177
|
end
|
178
178
|
|
179
179
|
it "should handle no actions" do
|
180
180
|
expected = { :action => "UNKNOWN_ACTION", :timestamp => "2010-09-21 23:15:20", :server => "Live", :app_name => 'Market' }
|
181
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
181
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 app_name=Market : server=Live")
|
182
182
|
actual.should == expected
|
183
183
|
end
|
184
184
|
|
185
185
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
186
186
|
expected = { :action => "address:=search-n", :timestamp => "2010-09-21 23:15:20" }
|
187
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
187
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n")
|
188
188
|
actual.should == expected
|
189
189
|
|
190
190
|
expected = { :action => "address::search==--n", :timestamp => "2010-09-21 23:15:20" }
|
191
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
191
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n")
|
192
192
|
actual.should == expected
|
193
193
|
end
|
194
194
|
|
195
195
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
196
196
|
expected = { :action => "address", :timestamp => "2010-09-21 23:15:20", :server => "market:eval=-n" }
|
197
|
-
actual = Appstats::Logger.entry_to_hash("0.19.
|
197
|
+
actual = Appstats::Logger.entry_to_hash("0.19.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n")
|
198
198
|
actual.should == expected
|
199
199
|
end
|
200
200
|
|
@@ -203,66 +203,66 @@ module Appstats
|
|
203
203
|
describe "#entry_to_s" do
|
204
204
|
|
205
205
|
it "should handle a statistics entry" do
|
206
|
-
expected = "0.19.
|
206
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search"
|
207
207
|
actual = Appstats::Logger.entry_to_s("address_search")
|
208
208
|
actual.should == expected
|
209
209
|
end
|
210
210
|
|
211
211
|
it "should handle numbers" do
|
212
|
-
expected = "0.19.
|
212
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=1 : note=2.2"
|
213
213
|
actual = Appstats::Logger.entry_to_s(1,:note => 2.2)
|
214
214
|
actual.should == expected
|
215
215
|
end
|
216
216
|
|
217
217
|
it "should handle default contexts" do
|
218
218
|
Appstats::Logger.default_contexts[:app_name] = "market"
|
219
|
-
expected = "0.19.
|
219
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : app_name=market"
|
220
220
|
actual = Appstats::Logger.entry_to_s("address_search")
|
221
221
|
actual.should == expected
|
222
222
|
end
|
223
223
|
|
224
224
|
it "should handle contexts (and sort them by symbol)" do
|
225
|
-
expected = "0.19.
|
225
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_filter : app_name=Market : server=Live"
|
226
226
|
actual = Appstats::Logger.entry_to_s("address_filter", { :server => "Live", :app_name => 'Market' })
|
227
227
|
actual.should == expected
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should handle actions with the delimiter (and change the delimiter)" do
|
231
|
-
expected = "0.19.
|
231
|
+
expected = "0.19.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=search-n"
|
232
232
|
actual = Appstats::Logger.entry_to_s("address:=search-n")
|
233
233
|
actual.should == expected
|
234
234
|
|
235
|
-
expected = "0.19.
|
235
|
+
expected = "0.19.2 setup[:::,===,---n] 2010-09-21 23:15:20 action===address::search==--n"
|
236
236
|
actual = Appstats::Logger.entry_to_s("address::search==--n")
|
237
237
|
actual.should == expected
|
238
238
|
end
|
239
239
|
|
240
240
|
it "should handle contexts with the delimiter (and change the delimiter)" do
|
241
|
-
expected = "0.19.
|
241
|
+
expected = "0.19.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address :: server==market:eval=-n"
|
242
242
|
actual = Appstats::Logger.entry_to_s("address", :server => 'market:eval=-n')
|
243
243
|
actual.should == expected
|
244
244
|
end
|
245
245
|
|
246
246
|
it "should ignore spaces" do
|
247
|
-
expected = "0.19.
|
247
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address search"
|
248
248
|
actual = Appstats::Logger.entry_to_s("address search")
|
249
249
|
actual.should == expected
|
250
250
|
end
|
251
251
|
|
252
252
|
it "should convert newlines in action" do
|
253
|
-
expected = "0.19.
|
253
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_-nsearch"
|
254
254
|
actual = Appstats::Logger.entry_to_s("address_\nsearch")
|
255
255
|
actual.should == expected
|
256
256
|
end
|
257
257
|
|
258
258
|
it "should convert newlines in context" do
|
259
|
-
expected = "0.19.
|
259
|
+
expected = "0.19.2 setup[:,=,-n] 2010-09-21 23:15:20 action=address_search : blah=some-nlong-nstatement"
|
260
260
|
actual = Appstats::Logger.entry_to_s("address_search",:blah => "some\nlong\nstatement")
|
261
261
|
actual.should == expected
|
262
262
|
end
|
263
263
|
|
264
264
|
it "should convert newlines based on the delimiter" do
|
265
|
-
expected = "0.19.
|
265
|
+
expected = "0.19.2 setup[::,==,--n] 2010-09-21 23:15:20 action==address:=--nsearch-n"
|
266
266
|
actual = Appstats::Logger.entry_to_s("address:=\nsearch-n")
|
267
267
|
actual.should == expected
|
268
268
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -7,170 +7,170 @@ module Appstats
|
|
7
7
|
Time.stub!(:now).and_return(Time.parse('2010-09-21 23:15:20'))
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
10
|
+
describe "#initialize" do
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@query = Appstats::Query.new
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should set input to nil" do
|
17
|
+
@query.query.should == nil
|
18
|
+
@query.query_type.should == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "query_type" do
|
22
|
+
|
23
|
+
it "should allow simple objects" do
|
24
|
+
query = Appstats::Query.new(:query => "# logins", :query_type => "YetAnotherTestQuery")
|
25
|
+
query.query.should == "# logins"
|
26
|
+
query.query_type.should == "YetAnotherTestQuery"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should allow modules" do
|
30
|
+
query = Appstats::Query.new(:query => "# logins", :query_type => "Appstats::TestQuery")
|
31
|
+
query.query.should == "# logins"
|
32
|
+
query.query_type.should == "Appstats::TestQuery"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow sub modules" do
|
36
|
+
query = Appstats::Query.new(:query => "# logins", :query_type => "Appstats::Core::AnotherTestQuery")
|
37
|
+
query.query.should == "# logins"
|
38
|
+
query.query_type.should == "Appstats::Core::AnotherTestQuery"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should fail for invalid query type" do
|
42
|
+
|
43
|
+
lambda { Appstats::Query.new(:query => "# logins", :query_type => "x") }.should raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "default query type" do
|
49
|
+
|
50
|
+
it "should set the inputs to nil if input invalid" do
|
51
|
+
query = Appstats::Query.new(:query => "# myblahs today on xyz.localnet")
|
52
|
+
query.query = nil
|
53
|
+
query.action.should == nil
|
54
|
+
query.host.should == nil
|
55
|
+
query.date_range.should == DateRange.new
|
56
|
+
query.group_by.should == []
|
57
|
+
query.group_query_to_sql.should == nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set the action and host" do
|
61
|
+
query = Appstats::Query.new(:query => "# myblahs today on xyz.localnet")
|
62
|
+
query.action.should == "myblahs"
|
63
|
+
query.host.should == "xyz.localnet"
|
64
|
+
query.date_range.should == DateRange.parse("today")
|
65
|
+
query.group_by.should == []
|
66
|
+
query.group_query_to_sql.should == nil
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should understand the short hand 'on' instead of 'on server'" do
|
70
|
+
query = Appstats::Query.new(:query => "# myblahs on xyz.localnet")
|
71
|
+
query.action.should == "myblahs"
|
72
|
+
query.host.should == "xyz.localnet"
|
73
|
+
query.date_range.should == DateRange.new
|
74
|
+
query.group_by.should == []
|
75
|
+
query.group_query_to_sql.should == nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should understand the old 'on server' instead of new 'on'" do
|
79
|
+
query = Appstats::Query.new(:query => "# myblahs on server xyz.localnet")
|
80
|
+
query.action.should == "myblahs"
|
81
|
+
query.host.should == "xyz.localnet"
|
82
|
+
query.date_range.should == DateRange.new
|
83
|
+
query.group_by.should == []
|
84
|
+
query.group_query_to_sql.should == nil
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "group by" do
|
88
|
+
|
89
|
+
it "should handle single entry" do
|
90
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa")
|
91
|
+
query.group_by.should == ["aa"]
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should handle multi-entry" do
|
95
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa,bbbb")
|
96
|
+
query.group_by.should == ["aa","bbbb"]
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "contexts" do
|
102
|
+
|
103
|
+
it "should handle single entry" do
|
104
|
+
query = Appstats::Query.new(:query => "# myblahs where aa = bb or aa < ccc")
|
105
|
+
query.contexts.should == "aa = bb or aa < ccc"
|
106
|
+
query.parsed_contexts.should == [ { :context_key => "aa", :comparator => "=", :context_value => "bb" }, "or", { :context_key => "aa", :comparator => "<", :context_value => "ccc" } ]
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "distinct query_type" do
|
114
|
+
|
115
|
+
it "should use sql query_type queries" do
|
116
|
+
query = Appstats::Query.new(:query => "# stuff", :query_type => "Appstats::TestQuery")
|
117
|
+
query.query_to_sql.should == "select count(*) as num from appstats_test_objects"
|
118
|
+
query.group_query_to_sql.should == "select context_key_filter, context_value_filter, count(*) as num from (select 'name' as context_key_filter, name as context_value_filter from appstats_test_objects) results group by context_value_filter"
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
125
|
describe "#run" do
|
126
126
|
|
127
127
|
before(:each) do
|
128
128
|
Appstats::Entry.delete_all
|
129
129
|
end
|
130
130
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
131
|
+
describe "core search" do
|
132
|
+
it "should return 0 if no results" do
|
133
|
+
query = Appstats::Query.new(:query => "# blahs")
|
134
|
+
result = query.run
|
135
|
+
result.new_record?.should == false
|
136
|
+
result.should == Appstats::Result.new(:result_type => "on_demand", :query => "# blahs", :query_to_sql => query.query_to_sql, :count => 0, :action => "blahs", :group_by => nil, :db_username => 'root', :db_name => 'appstats_test', :db_host => 'localhost' )
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should set name and result_type if provided" do
|
140
|
+
query = Appstats::Query.new(:name => "x", :result_type => "some_reason", :query => "# blahs")
|
141
|
+
result = query.run
|
142
|
+
result.new_record?.should == false
|
143
|
+
result.should == Appstats::Result.new(:name => "x", :result_type => "some_reason", :query => "# blahs", :query_to_sql => query.query_to_sql, :count => 0, :action => "blahs", :group_by => nil, :db_username => 'root', :db_name => 'appstats_test', :db_host => 'localhost')
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should track contexts" do
|
147
|
+
query = Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)")
|
148
|
+
result = query.run
|
149
|
+
result.new_record?.should == false
|
150
|
+
result.contexts.should == "(a=b and c=4) or (aaa=5)"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should track the count if available" do
|
154
|
+
Appstats::Entry.create(:action => "myblahs")
|
155
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
156
|
+
query.run.count.should == 1
|
157
|
+
Appstats::Entry.create(:action => "myblahs")
|
158
|
+
query.run.count.should == 2
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should track query_duration_in_seconds" do
|
162
|
+
timer = FriendlyTimer.new(:duration => 10.0)
|
163
|
+
timer.stub!(:stop)
|
164
|
+
FriendlyTimer.stub!(:new).and_return(timer)
|
165
|
+
|
166
|
+
Appstats::Entry.create(:action => "myblahs")
|
167
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
168
|
+
result = query.run
|
169
|
+
|
170
|
+
result.query_duration_in_seconds.should == 10.0
|
171
|
+
result.group_query_duration_in_seconds.should == nil
|
172
|
+
end
|
173
|
+
|
174
174
|
it "should track group_query_duration_in_seconds if a group provided" do
|
175
175
|
timer = FriendlyTimer.new(:duration => 10.0)
|
176
176
|
timer.stub!(:stop)
|
@@ -183,509 +183,538 @@ module Appstats
|
|
183
183
|
result.query_duration_in_seconds.should == 10.0
|
184
184
|
result.group_query_duration_in_seconds.should == 10.0
|
185
185
|
end
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
#
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
#
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
#
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
#
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
#
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
#
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
186
|
+
|
187
|
+
it "should not double count an entry with multiple contexts" do
|
188
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","b"])
|
189
|
+
query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
|
190
|
+
query.run.count.should == 1
|
191
|
+
|
192
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["a","c"])
|
193
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["b","d"])
|
194
|
+
Appstats::Entry.create_from_logger("myblahs",:app_name => ["c","d"])
|
195
|
+
query = Appstats::Query.new(:query => "# myblahs where app_name='a' or app_name = 'b'")
|
196
|
+
query.run.count.should == 3
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
it "should perform the action search" do
|
202
|
+
Appstats::Entry.create_from_logger("myblahs", :one => "11", :two => "222")
|
203
|
+
Appstats::Entry.create_from_logger("myblahs", :one => "111", :two => "22")
|
204
|
+
|
205
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11")
|
206
|
+
result = query.run
|
207
|
+
result.count.should == 1
|
208
|
+
|
209
|
+
query = Appstats::Query.new(:query => "# myblahs where one=anything")
|
210
|
+
query.run.count.should == 0
|
211
|
+
|
212
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11 && two=22")
|
213
|
+
query.run.count.should == 0
|
214
|
+
|
215
|
+
query = Appstats::Query.new(:query => "# myblahs where one=11 || two=22")
|
216
|
+
query.run.count.should == 2
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "fixed_points searches" do
|
220
|
+
|
221
|
+
it "should handle year" do
|
222
|
+
query = Appstats::Query.new(:query => "# myblahs last year")
|
223
|
+
result = query.run
|
224
|
+
result.date_to_s.should == "2009-01-01 to 2009-12-31"
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should handle quarter" do
|
228
|
+
query = Appstats::Query.new(:query => "# myblahs last quarter")
|
229
|
+
result = query.run
|
230
|
+
result.date_to_s.should == "2010-04-01 to 2010-06-30"
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should handle month" do
|
234
|
+
query = Appstats::Query.new(:query => "# myblahs last month")
|
235
|
+
result = query.run
|
236
|
+
result.date_to_s.should == "2010-08-01 to 2010-08-31"
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should handle week" do
|
240
|
+
query = Appstats::Query.new(:query => "# myblahs last week")
|
241
|
+
result = query.run
|
242
|
+
result.date_to_s.should == "2010-09-13 to 2010-09-19"
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should handle day" do
|
246
|
+
query = Appstats::Query.new(:query => "# myblahs last day")
|
247
|
+
result = query.run
|
248
|
+
result.date_to_s.should == "2010-09-20"
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe "real examples" do
|
253
|
+
|
254
|
+
it "nil split being called" do
|
255
|
+
query = Appstats::Query.new(:query => "# buyer-address-lookups group by city", :query_type => "Appstats::InvalidTestQuery")
|
256
|
+
result = query.run
|
257
|
+
result.count.should == 0
|
258
|
+
result.sub_results.size.should == 0
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
describe "group sub results" do
|
266
|
+
|
267
|
+
before(:each) do
|
268
|
+
Appstats::Entry.delete_all
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should not create sub results if no group_by" do
|
272
|
+
query = Appstats::Query.new(:query => "# myblahs last day")
|
273
|
+
result = query.run
|
274
|
+
result.sub_results.should == []
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should track elements outside of the context" do
|
278
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a")
|
279
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a")
|
280
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a")
|
281
|
+
Appstats::Entry.create_from_logger("myblahs")
|
282
|
+
|
283
|
+
query = Appstats::Query.new(:query => "# myblahs group by service_provider")
|
284
|
+
result = query.run
|
285
|
+
result.count.should == 4
|
286
|
+
result.sub_results.size.should == 2
|
287
|
+
result.sub_results[0].should == SubResult.new(:context_filter => "a", :count => 3, :ratio_of_total => 0.75)
|
288
|
+
result.sub_results[1].should == SubResult.new(:context_filter => nil, :count => 1, :ratio_of_total => 0.25)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should track empty and nil contexts" do
|
292
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a")
|
293
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a")
|
294
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "")
|
295
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => nil)
|
296
|
+
|
297
|
+
query = Appstats::Query.new(:query => "# myblahs group by service_provider")
|
298
|
+
result = query.run
|
299
|
+
result.count.should == 4
|
300
|
+
result.sub_results.size.should == 2
|
301
|
+
result.sub_results[0].should == SubResult.new(:context_filter => "", :count => 2, :ratio_of_total => 0.5)
|
302
|
+
result.sub_results[1].should == SubResult.new(:context_filter => "a", :count => 2, :ratio_of_total => 0.5)
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
it "should track sub results for single group by" do
|
307
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
|
308
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "1")
|
309
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :ignore => "2")
|
310
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :ignore => "1")
|
311
|
+
|
312
|
+
query = Appstats::Query.new(:query => "# myblahs group by service_provider")
|
313
|
+
result = query.run
|
314
|
+
result.count.should == 4
|
315
|
+
result.group_by.should == "service_provider"
|
316
|
+
result.sub_results.size.should == 2
|
317
|
+
result.group_query_to_sql.should == query.group_query_to_sql
|
318
|
+
|
319
|
+
result.sub_results[0].should == SubResult.new(:context_filter => "a", :count => 3, :ratio_of_total => 0.75)
|
320
|
+
result.sub_results[1].should == SubResult.new(:context_filter => "b", :count => 1, :ratio_of_total => 0.25)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should track sub results for multiple group by" do
|
324
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "1")
|
325
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "1")
|
326
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "1")
|
327
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "1")
|
328
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "1")
|
329
|
+
|
330
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "2")
|
331
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "a", :user => "2")
|
332
|
+
|
333
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :user => "1")
|
334
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :user => "1")
|
335
|
+
Appstats::Entry.create_from_logger("myblahs",:service_provider => "b", :user => "1")
|
336
|
+
|
337
|
+
query = Appstats::Query.new(:query => "# myblahs group by service_provider,user")
|
338
|
+
result = query.run
|
339
|
+
result.count.should == 10
|
340
|
+
result.group_by.should == "service_provider, user"
|
341
|
+
result.sub_results.size.should == 3
|
342
|
+
|
343
|
+
result.sub_results[0].should == SubResult.new(:context_filter => "a, 1", :count => 5, :ratio_of_total => 0.50)
|
344
|
+
result.sub_results[1].should == SubResult.new(:context_filter => "b, 1", :count => 3, :ratio_of_total => 0.30)
|
345
|
+
result.sub_results[2].should == SubResult.new(:context_filter => "a, 2", :count => 2, :ratio_of_total => 0.20)
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
describe "third party searches" do
|
351
|
+
|
352
|
+
before(:each) do
|
353
|
+
TestObject.delete_all
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should handle custom sql" do
|
358
|
+
TestObject.create and TestObject.create
|
359
|
+
|
360
|
+
query = Query.new(:query => "# x", :query_type => "Appstats::TestQuery")
|
361
|
+
result = query.run
|
362
|
+
|
363
|
+
result.query_type.should == "Appstats::TestQuery"
|
364
|
+
result.count.should == 2
|
365
|
+
result.query_to_sql.should == "select count(*) as num from appstats_test_objects"
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should track db connection on custom sql" do
|
369
|
+
query = Query.new(:query => "# x on otherServer", :query_type => "Appstats::TestQuery")
|
370
|
+
result = query.run
|
371
|
+
[result.db_username,result.db_name,result.db_host].should == ['root','appstats_development','localhost']
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should handle group by errors" do
|
375
|
+
query = Query.new(:query => "# x group by y", :query_type => "Appstats::BadGroupTestQuery")
|
376
|
+
result = query.run
|
377
|
+
result.query_type.should == "Appstats::BadGroupTestQuery"
|
378
|
+
result.sub_results.should == [ Appstats::SubResult.new(:context_filter => nil, :count => 2, :ratio_of_total => 1.0) ]
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should reset database if things fail" do
|
382
|
+
query = Query.new(:query => "# x", :query_type => "Appstats::BadTestQuery")
|
383
|
+
result = query.run
|
384
|
+
result.query_type.should == "Appstats::BadTestQuery"
|
385
|
+
result.count.should == nil
|
386
|
+
|
387
|
+
ActiveRecord::Base.connection.current_database.should == YAML::load(File.open('db/config.yml'))["test"]["database"]
|
388
|
+
end
|
389
|
+
|
390
|
+
|
391
|
+
it "should handle group by" do
|
392
|
+
TestObject.create(:name => "aa") and TestObject.create(:name => "aa") and TestObject.create(:name => "bb")
|
393
|
+
|
394
|
+
query = Query.new(:query => "# x group by y", :query_type => "Appstats::TestQuery")
|
395
|
+
result = query.run
|
396
|
+
|
397
|
+
result.query_type.should == "Appstats::TestQuery"
|
398
|
+
result.count.should == 3
|
399
|
+
result.group_query_to_sql.should == "select context_key_filter, context_value_filter, count(*) as num from (select 'name' as context_key_filter, name as context_value_filter from appstats_test_objects) results group by context_value_filter"
|
400
|
+
result.sub_results.size.should == 2
|
401
|
+
end
|
402
|
+
|
403
|
+
it "should handle remote servers" do
|
404
|
+
TestObject.create(:name => "aa")
|
405
|
+
|
406
|
+
query1 = Query.new(:query => "# x on testServer", :query_type => "Appstats::TestQuery")
|
407
|
+
result1 = query1.run
|
408
|
+
|
409
|
+
query2 = Query.new(:query => "# x on otherServer", :query_type => "Appstats::TestQuery")
|
410
|
+
result2 = query2.run
|
411
|
+
|
412
|
+
if result2.count == result1.count #coincidence
|
413
|
+
TestObject.create(:name => "aa")
|
414
|
+
result2 = query2.run
|
415
|
+
end
|
416
|
+
|
417
|
+
result1.count.should_not == result2.count
|
418
|
+
|
419
|
+
result1 = query1.run
|
420
|
+
result1.count.should_not == result2.count
|
421
|
+
end
|
422
|
+
|
423
|
+
end
|
424
|
+
|
425
|
+
end
|
426
|
+
|
427
|
+
|
428
|
+
describe "#query_to_sql" do
|
429
|
+
|
430
|
+
before(:all) do
|
431
|
+
Appstats::Action.delete_all
|
432
|
+
Appstats::Action.create(:name => "login", :plural_name => "logins")
|
433
|
+
end
|
434
|
+
|
435
|
+
it "should return understand nil" do
|
436
|
+
expected_sql = "select 0 from appstats_entries LIMIT 1"
|
437
|
+
Appstats::Query.new(:query => nil).query_to_sql.should == expected_sql
|
438
|
+
Appstats::Query.new(:query => "").query_to_sql.should == expected_sql
|
439
|
+
Appstats::Query.new.query_to_sql.should == expected_sql
|
440
|
+
end
|
441
|
+
|
442
|
+
describe "actions" do
|
443
|
+
|
444
|
+
it "should understand both singular and plural names" do
|
445
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'login'"
|
446
|
+
Appstats::Query.new(:query => "# logins").query_to_sql.should == expected_sql
|
447
|
+
Appstats::Query.new(:query => "# login").query_to_sql.should == expected_sql
|
448
|
+
end
|
449
|
+
|
450
|
+
it "should use 'itself' if action not found" do
|
451
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'garblygook'"
|
452
|
+
Appstats::Query.new(:query => "# garblygook").query_to_sql.should == expected_sql
|
453
|
+
end
|
454
|
+
|
455
|
+
end
|
456
|
+
|
457
|
+
describe "date ranges" do
|
458
|
+
it "should understand since dates" do
|
459
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'login' and occurred_at >= '2010-01-15 00:00:00'"
|
460
|
+
Appstats::Query.new(:query => "# logins since 2010-01-15").query_to_sql.should == expected_sql
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
describe "server_name" do
|
465
|
+
|
466
|
+
it "should on_name" do
|
467
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'login' and EXISTS (select * from appstats_log_collectors where appstats_entries.appstats_log_collector_id = appstats_log_collectors.id and host = 'my.localnet' )"
|
468
|
+
Appstats::Query.new(:query => "# logins on my.localnet").query_to_sql.should == expected_sql
|
469
|
+
end
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
describe "date range and server_name" do
|
474
|
+
it "should understand dates and 'on'" do
|
475
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'login' and (occurred_at >= '2010-01-15 00:00:00' and occurred_at <= '2010-01-31 23:59:59') and EXISTS (select * from appstats_log_collectors where appstats_entries.appstats_log_collector_id = appstats_log_collectors.id and host = 'your.localnet' )"
|
476
|
+
Appstats::Query.new(:query => "# logins between 2010-01-15 and 2010-01-31 on your.localnet").query_to_sql.should == expected_sql
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
describe "where clause" do
|
481
|
+
|
482
|
+
it "should understand no quotes" do
|
483
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'login' and EXISTS (select * from appstats_contexts where appstats_entries.id = appstats_contexts.appstats_entry_id and ( (context_key = 'user' and context_value = 'aforward')))"
|
484
|
+
Appstats::Query.new(:query => "# logins where user = aforward").query_to_sql.should == expected_sql
|
485
|
+
end
|
486
|
+
|
487
|
+
it "should handle example" do
|
488
|
+
expected_sql = "select count(*) as num from appstats_entries where action = 'blahs' and EXISTS (select * from appstats_contexts where appstats_entries.id = appstats_contexts.appstats_entry_id and ( ( (context_key = 'a' and context_value = 'b') and (context_key = 'c' and context_value = '4') ) or ( (context_key = 'aaa' and context_value = '5') )))"
|
489
|
+
Appstats::Query.new(:query => "# blahs where (a=b and c=4) or (aaa=5)").query_to_sql.should == expected_sql
|
490
|
+
end
|
491
|
+
|
492
|
+
end
|
493
|
+
|
494
|
+
end
|
495
|
+
|
496
|
+
describe "#host_filter_to_sql" do
|
497
|
+
|
498
|
+
it "should translate blah into EXISTS query" do
|
499
|
+
expected = "EXISTS (select * from appstats_log_collectors where appstats_entries.appstats_log_collector_id = appstats_log_collectors.id and host = 'a' )"
|
500
|
+
Appstats::Query.host_filter_to_sql("a").should == expected
|
501
|
+
Appstats::Query.host_filter_to_sql(" a ").should == expected
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should ignore single quotes and spaces" do
|
505
|
+
Appstats::Query.host_filter_to_sql("bl'ah").should == "1=1"
|
506
|
+
Appstats::Query.host_filter_to_sql("bl ah").should == "1=1"
|
507
|
+
end
|
508
|
+
|
509
|
+
it "should do simple 1=1 if invalid" do
|
510
|
+
Appstats::Query.host_filter_to_sql("").should == "1=1"
|
511
|
+
Appstats::Query.host_filter_to_sql(nil).should == "1=1"
|
512
|
+
end
|
513
|
+
|
514
|
+
end
|
515
|
+
|
516
|
+
describe "#group_query_to_sql" do
|
517
|
+
|
518
|
+
before(:each) do
|
519
|
+
@template = "select id from appstats_entries where action = 'myblahs'"
|
520
|
+
end
|
521
|
+
|
522
|
+
it "should support no filters" do
|
523
|
+
query = Appstats::Query.new(:query => "# myblahs")
|
524
|
+
query.group_query_to_sql.should == nil
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should support 1 filter" do
|
528
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa")
|
529
|
+
expected = "select context_key_filter, context_value_filter, count(*) as num from (select group_concat(appstats_contexts.context_key) as context_key_filter, group_concat(appstats_contexts.context_value) as context_value_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_value_filter"
|
530
|
+
query.group_query_to_sql.should == expected
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should support surrounding quotes" do
|
534
|
+
query = Appstats::Query.new(:query => "# myblahs group by 'aa'")
|
535
|
+
expected = "select context_key_filter, context_value_filter, count(*) as num from (select group_concat(appstats_contexts.context_key) as context_key_filter, group_concat(appstats_contexts.context_value) as context_value_filter, appstats_entry_id from appstats_contexts where context_key in ('aa') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_value_filter"
|
536
|
+
query.group_query_to_sql.should == expected
|
537
|
+
end
|
538
|
+
|
539
|
+
it "should support inner quotes" do
|
540
|
+
query = Appstats::Query.new(:query => "# myblahs group by a's")
|
541
|
+
expected = "select context_key_filter, context_value_filter, count(*) as num from (select group_concat(appstats_contexts.context_key) as context_key_filter, group_concat(appstats_contexts.context_value) as context_value_filter, appstats_entry_id from appstats_contexts where context_key in ('a''s') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_value_filter"
|
542
|
+
query.group_query_to_sql.should == expected
|
543
|
+
end
|
544
|
+
|
545
|
+
|
546
|
+
it "should support many filters" do
|
547
|
+
query = Appstats::Query.new(:query => "# myblahs group by aa, bbb")
|
548
|
+
expected = "select context_key_filter, context_value_filter, count(*) as num from (select group_concat(appstats_contexts.context_key) as context_key_filter, group_concat(appstats_contexts.context_value) as context_value_filter, appstats_entry_id from appstats_contexts where context_key in ('aa','bbb') and appstats_entry_id in ( #{@template} ) group by appstats_entry_id) results group by context_value_filter"
|
549
|
+
query.group_query_to_sql.should == expected
|
550
|
+
end
|
551
|
+
|
552
|
+
|
553
|
+
end
|
554
|
+
|
555
|
+
describe "#contexts_filter_to_sql" do
|
556
|
+
|
557
|
+
before(:each) do
|
558
|
+
@template = "EXISTS (select * from appstats_contexts where appstats_entries.id = appstats_contexts.appstats_entry_id and ("
|
559
|
+
end
|
560
|
+
|
561
|
+
it "should translate a = b into EXISTS query" do
|
562
|
+
Appstats::Query.new(:query => "# logins where a=b").contexts_filter_to_sql.should == "#{@template} (context_key = 'a' and context_value = 'b')))"
|
563
|
+
Appstats::Query.new(:query => "# logins where a = b ").contexts_filter_to_sql.should == "#{@template} (context_key = 'a' and context_value = 'b')))"
|
564
|
+
end
|
565
|
+
|
566
|
+
it "should ignore single quotes" do
|
567
|
+
Appstats::Query.new(:query => "# logins where 'aaa'='bbbb'").contexts_filter_to_sql.should == "#{@template} (context_key = 'aaa' and context_value = 'bbbb')))"
|
568
|
+
Appstats::Query.new(:query => "# logins where 'aaa' = 'bbbb' ").contexts_filter_to_sql.should == "#{@template} (context_key = 'aaa' and context_value = 'bbbb')))"
|
569
|
+
end
|
570
|
+
|
571
|
+
it "should allow for searching for all entries of a certain context" do
|
572
|
+
Appstats::Query.new(:query => "# logins where aaa").contexts_filter_to_sql.should == "#{@template} (context_key = 'aaa')))"
|
573
|
+
end
|
574
|
+
|
575
|
+
it "should allow for searching for several entries of a certain context" do
|
576
|
+
Appstats::Query.new(:query => "# logins where aaa || bbb").contexts_filter_to_sql.should == "#{@template} (context_key = 'aaa') or (context_key = 'bbb')))"
|
577
|
+
end
|
578
|
+
|
579
|
+
it "should allow complex queries" do
|
580
|
+
Appstats::Query.new(:query => "# logins where user='andrew' || user='aforward'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value = 'andrew') or (context_key = 'user' and context_value = 'aforward')))"
|
581
|
+
end
|
582
|
+
|
583
|
+
it "should support or" do
|
584
|
+
Appstats::Query.new(:query => "# logins where user='andrew' or user='aforward'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value = 'andrew') or (context_key = 'user' and context_value = 'aforward')))"
|
585
|
+
end
|
586
|
+
|
587
|
+
it "should support like" do
|
588
|
+
Appstats::Query.new(:query => "# logins where user like '%andrew%'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value like '%andrew%')))"
|
589
|
+
end
|
590
|
+
|
591
|
+
it "should support and" do
|
592
|
+
Appstats::Query.new(:query => "# logins where user='andrew' and user='aforward'").contexts_filter_to_sql.should == "#{@template} (context_key = 'user' and context_value = 'andrew') and (context_key = 'user' and context_value = 'aforward')))"
|
593
|
+
end
|
594
|
+
|
595
|
+
|
596
|
+
it "should do simple 1 = 1 if invalid" do
|
597
|
+
Appstats::Query.new(:query => "# logins where").contexts_filter_to_sql.should == "1=1"
|
598
|
+
Appstats::Query.new(:query => "# logins").contexts_filter_to_sql.should == "1=1"
|
599
|
+
end
|
600
|
+
|
601
|
+
end
|
602
|
+
|
603
|
+
describe "#sqlize" do
|
604
|
+
|
605
|
+
it "should handle nil" do
|
606
|
+
Appstats::Query.sqlize(nil).should == nil
|
607
|
+
Appstats::Query.sqlize('').should == ''
|
608
|
+
end
|
609
|
+
|
610
|
+
it "should understand &&" do
|
611
|
+
Appstats::Query.sqlize("&&").should == "and"
|
612
|
+
end
|
613
|
+
|
614
|
+
it "should understand ||" do
|
615
|
+
Appstats::Query.sqlize("||").should == "or"
|
616
|
+
end
|
617
|
+
|
618
|
+
it "should understand !=" do
|
619
|
+
Appstats::Query.sqlize("!=").should == "<>"
|
620
|
+
end
|
621
|
+
|
622
|
+
it "should set everything else as-is" do
|
623
|
+
Appstats::Query.sqlize("blah").should == "blah"
|
624
|
+
end
|
625
|
+
|
626
|
+
end
|
627
|
+
|
628
|
+
describe "#sqlclean" do
|
629
|
+
|
630
|
+
it "should handle nil" do
|
631
|
+
Appstats::Query.sqlclean(nil).should == nil
|
632
|
+
Appstats::Query.sqlclean('').should == ''
|
633
|
+
end
|
634
|
+
|
635
|
+
it "should remove exterior quotes" do
|
636
|
+
Appstats::Query.sqlclean("'a'").should == "a"
|
637
|
+
Appstats::Query.sqlclean("'bbb'").should == "bbb"
|
638
|
+
Appstats::Query.sqlclean('"a"').should == "a"
|
639
|
+
Appstats::Query.sqlclean('"bbb"').should == "bbb"
|
640
|
+
end
|
641
|
+
|
642
|
+
it "should handle normal text" do
|
643
|
+
Appstats::Query.sqlclean('abc').should == 'abc'
|
644
|
+
end
|
645
|
+
|
646
|
+
it "should handle slashes" do
|
647
|
+
Appstats::Query.sqlclean('a\b').should == 'a\\\\b'
|
648
|
+
end
|
649
|
+
|
650
|
+
it "should handle single quotes" do
|
651
|
+
Appstats::Query.sqlclean("a'b").should == "a''b"
|
652
|
+
end
|
653
|
+
|
654
|
+
end
|
655
|
+
|
656
|
+
describe "#comparators" do
|
657
|
+
|
658
|
+
it "should be a list " do
|
659
|
+
Appstats::Query.comparators.should == ["=","!=","<>",">","<",">=","<=","like"]
|
660
|
+
end
|
661
|
+
|
662
|
+
end
|
663
|
+
|
664
|
+
describe "#comparator?" do
|
665
|
+
|
666
|
+
it "should not consider nil" do
|
667
|
+
Appstats::Query.comparator?(nil).should == false
|
668
|
+
Appstats::Query.comparator?("").should == false
|
669
|
+
end
|
670
|
+
|
671
|
+
|
672
|
+
it "should not consider &&" do
|
673
|
+
Appstats::Query.comparator?("&&").should == false
|
674
|
+
end
|
675
|
+
|
676
|
+
it "should not consider ||" do
|
677
|
+
Appstats::Query.comparator?("||").should == false
|
678
|
+
end
|
679
|
+
|
680
|
+
it "should not consider and" do
|
681
|
+
Appstats::Query.comparator?("and").should == false
|
682
|
+
end
|
683
|
+
|
684
|
+
it "should not consider or" do
|
685
|
+
Appstats::Query.comparator?("or").should == false
|
686
|
+
end
|
687
|
+
|
688
|
+
it "should consider =" do
|
689
|
+
Appstats::Query.comparator?("=").should == true
|
690
|
+
end
|
691
|
+
|
692
|
+
it "should consider !=" do
|
693
|
+
Appstats::Query.comparator?("!=").should == true
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should consider <>" do
|
697
|
+
Appstats::Query.comparator?("<>").should == true
|
698
|
+
end
|
699
|
+
|
700
|
+
it "should consider >" do
|
701
|
+
Appstats::Query.comparator?(">").should == true
|
702
|
+
end
|
703
|
+
|
704
|
+
it "should consider <" do
|
705
|
+
Appstats::Query.comparator?("<").should == true
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should consider >=" do
|
709
|
+
Appstats::Query.comparator?(">=").should == true
|
710
|
+
end
|
711
|
+
|
712
|
+
it "should consider <=" do
|
713
|
+
Appstats::Query.comparator?("<=").should == true
|
714
|
+
end
|
715
|
+
|
716
|
+
|
717
|
+
end
|
689
718
|
|
690
719
|
|
691
720
|
|