flipsasser-bullet 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ module Bullet
2
+ class BulletLogger < Logger
3
+ LOG_FILE = ::RAILS_ROOT + '/log/bullet.log'
4
+
5
+ def format_message(severity, timestamp, progname, msg)
6
+ "#{timestamp.to_formatted_s(:db)}[#{severity}] #{msg}\n"
7
+ end
8
+ end
9
+ end
data/lib/bulletware.rb ADDED
@@ -0,0 +1,25 @@
1
+ class Bulletware
2
+ def initialize(app)
3
+ @app = app
4
+ end
5
+
6
+ def call(env)
7
+ return @app.call(env) unless Bullet.enable?
8
+
9
+ Bullet::Association.start_request
10
+ status, headers, response = @app.call(env)
11
+ return [status, headers, response] if response.empty?
12
+
13
+ if Bullet::Association.has_bad_assocations?
14
+ if !headers['Content-Type'].nil? and headers['Content-Type'].include? 'text/html'
15
+ response_body = response.body << Bullet::Association.bad_associations_alert
16
+ headers['Content-Length'] = response_body.length.to_s
17
+ end
18
+
19
+ Bullet::Association.log_bad_associations(env['PATH_INFO'])
20
+ end
21
+ response_body ||= response.body
22
+ Bullet::Association.end_request
23
+ [status, headers, response_body]
24
+ end
25
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'bullet'
@@ -0,0 +1,696 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :dbfile => ':memory:')
3
+
4
+ describe Bullet::Association, 'has_many' do
5
+ def setup_db
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table :categories do |t|
8
+ t.column :name, :string
9
+ end
10
+
11
+ create_table :posts do |t|
12
+ t.column :name, :string
13
+ t.column :category_id, :integer
14
+ end
15
+
16
+ create_table :comments do |t|
17
+ t.column :name, :string
18
+ t.column :post_id, :integer
19
+ end
20
+
21
+ create_table :entries do |t|
22
+ t.column :name, :string
23
+ t.column :category_id, :integer
24
+ end
25
+ end
26
+ end
27
+
28
+ def teardown_db
29
+ ActiveRecord::Base.connection.tables.each do |table|
30
+ ActiveRecord::Base.connection.drop_table(table)
31
+ end
32
+ end
33
+
34
+ class Category < ActiveRecord::Base
35
+ has_many :posts
36
+ has_many :entries
37
+ end
38
+
39
+ class Post < ActiveRecord::Base
40
+ belongs_to :category
41
+ has_many :comments
42
+ end
43
+
44
+ class Entry < ActiveRecord::Base
45
+ belongs_to :category
46
+ end
47
+
48
+ class Comment < ActiveRecord::Base
49
+ belongs_to :post
50
+ end
51
+
52
+ before(:all) do
53
+ setup_db
54
+
55
+ category1 = Category.create(:name => 'first')
56
+ category2 = Category.create(:name => 'second')
57
+
58
+ post1 = category1.posts.create(:name => 'first')
59
+ post2 = category1.posts.create(:name => 'second')
60
+ post3 = category2.posts.create(:name => 'third')
61
+ post4 = category2.posts.create(:name => 'fourth')
62
+
63
+ comment1 = post1.comments.create(:name => 'first')
64
+ comment2 = post1.comments.create(:name => 'second')
65
+ comment3 = post2.comments.create(:name => 'third')
66
+ comment4 = post2.comments.create(:name => 'fourth')
67
+
68
+ entry1 = category1.entries.create(:name => 'first')
69
+ entry2 = category1.entries.create(:name => 'second')
70
+ end
71
+
72
+ after(:all) do
73
+ teardown_db
74
+ end
75
+
76
+ before(:each) do
77
+ Bullet::Association.start_request
78
+ end
79
+
80
+ after(:each) do
81
+ Bullet::Association.end_request
82
+ end
83
+
84
+ context "post => comments" do
85
+ it "should detect preload with post => comments" do
86
+ Post.find(:all, :include => :comments).each do |post|
87
+ post.comments.collect(&:name)
88
+ end
89
+ Bullet::Association.should_not be_has_unpreload_associations
90
+ end
91
+
92
+ it "should detect no preload post => comments" do
93
+ Post.find(:all).each do |post|
94
+ post.comments.collect(&:name)
95
+ end
96
+ Bullet::Association.should be_has_unpreload_associations
97
+ end
98
+
99
+ it "should detect unused preload post => comments" do
100
+ Post.find(:all, :include => :comments).collect(&:name)
101
+ Bullet::Association.check_unused_preload_associations
102
+ Bullet::Association.should be_has_unused_preload_associations
103
+ end
104
+
105
+ it "should no detect unused preload post => comments" do
106
+ Post.find(:all).collect(&:name)
107
+ Bullet::Association.check_unused_preload_associations
108
+ Bullet::Association.should_not be_has_unused_preload_associations
109
+ end
110
+ end
111
+
112
+ context "category => posts => comments" do
113
+ it "should detect preload with category => posts => comments" do
114
+ Category.find(:all, :include => {:posts => :comments}) do |category|
115
+ category.posts.each do |post|
116
+ post.comments.collect(&:name)
117
+ end
118
+ end
119
+ Bullet::Association.should_not be_has_unpreload_associations
120
+ end
121
+
122
+ it "should detect preload category => posts, but no post => comments" do
123
+ Category.find(:all, :include => :posts).each do |category|
124
+ category.posts.each do |post|
125
+ post.comments.collect(&:name)
126
+ end
127
+ end
128
+ Bullet::Association.should be_has_unpreload_associations
129
+ end
130
+
131
+ it "should detect no preload category => posts => comments" do
132
+ Category.find(:all).each do |category|
133
+ category.posts.each do |post|
134
+ post.comments.collect(&:name)
135
+ end
136
+ end
137
+ Bullet::Association.should be_has_unpreload_associations
138
+ end
139
+
140
+ it "should detect unused preload with category => posts => comments" do
141
+ Category.find(:all, :include => {:posts => :comments}).collect(&:name)
142
+ Bullet::Association.check_unused_preload_associations
143
+ Bullet::Association.should be_has_unused_preload_associations
144
+ end
145
+
146
+ it "should detect unused preload with post => commnets, no category => posts" do
147
+ Category.find(:all, :include => {:posts => :comments}).each do |category|
148
+ category.posts.collect(&:name)
149
+ end
150
+ Bullet::Association.check_unused_preload_associations
151
+ Bullet::Association.should be_has_unused_preload_associations
152
+ end
153
+
154
+ it "should no detect preload with category => posts => comments" do
155
+ Category.find(:all).each do |category|
156
+ category.posts.each do |post|
157
+ post.comments.collect(&:name)
158
+ end
159
+ end
160
+ Bullet::Association.check_unused_preload_associations
161
+ Bullet::Association.should_not be_has_unused_preload_associations
162
+ end
163
+ end
164
+
165
+ context "category => posts, category => entries" do
166
+ it "should detect preload with category => [posts, entries]" do
167
+ Category.find(:all, :include => [:posts, :entries]).each do |category|
168
+ category.posts.collect(&:name)
169
+ category.entries.collect(&:name)
170
+ end
171
+ Bullet::Association.should_not be_has_unpreload_associations
172
+ end
173
+
174
+ it "should detect preload with category => posts, but no category => entries" do
175
+ Category.find(:all, :include => :posts).each do |category|
176
+ category.posts.collect(&:name)
177
+ category.entries.collect(&:name)
178
+ end
179
+ Bullet::Association.should be_has_unpreload_associations
180
+ end
181
+
182
+ it "should detect no preload with category => [posts, entries]" do
183
+ Category.find(:all).each do |category|
184
+ category.posts.collect(&:name)
185
+ category.entries.collect(&:name)
186
+ end
187
+ Bullet::Association.should be_has_unpreload_associations
188
+ end
189
+
190
+ it "should detect unused with category => [posts, entries]" do
191
+ Category.find(:all, :include => [:posts, :entries]).collect(&:name)
192
+ Bullet::Association.check_unused_preload_associations
193
+ Bullet::Association.should be_has_unused_preload_associations
194
+ end
195
+
196
+ it "should detect unused preload with category => entries, but no category => posts" do
197
+ Category.find(:all, :include => [:posts, :entries]).each do |category|
198
+ category.posts.collect(&:name)
199
+ end
200
+ Bullet::Association.check_unused_preload_associations
201
+ Bullet::Association.should be_has_unused_preload_associations
202
+ end
203
+
204
+ it "should detect no unused preload" do
205
+ Category.find(:all).each do |category|
206
+ category.posts.collect(&:name)
207
+ category.entries.collect(&:name)
208
+ end
209
+ Bullet::Association.check_unused_preload_associations
210
+ Bullet::Association.should_not be_has_unused_preload_associations
211
+ end
212
+ end
213
+
214
+ context "no preload" do
215
+ it "should no preload only one post => commnets" do
216
+ Post.first.comments.collect(&:name)
217
+ Bullet::Association.should_not be_has_unpreload_associations
218
+ end
219
+ end
220
+
221
+ context "belongs_to" do
222
+ it "should preload comments => post" do
223
+ Comment.find(:all).each do |comment|
224
+ comment.post.name
225
+ end
226
+ Bullet::Association.should be_has_unpreload_associations
227
+ end
228
+
229
+ it "should no preload comment => post" do
230
+ Comment.first.post.name
231
+ Bullet::Association.should_not be_has_unpreload_associations
232
+ end
233
+
234
+ it "should no preload comments => post" do
235
+ Comment.find(:all, :include => :post).each do |comment|
236
+ comment.post.name
237
+ end
238
+ Bullet::Association.should_not be_has_unpreload_associations
239
+ end
240
+
241
+ it "should detect no unused preload comments => post" do
242
+ Comment.find(:all).collect(&:name)
243
+ Bullet::Association.check_unused_preload_associations
244
+ Bullet::Association.should_not be_has_unused_preload_associations
245
+ end
246
+
247
+ it "should detect unused preload comments => post" do
248
+ Comment.find(:all, :include => :post).collect(&:name)
249
+ Bullet::Association.check_unused_preload_associations
250
+ Bullet::Association.should be_has_unused_preload_associations
251
+ end
252
+
253
+ it "should dectect no unused preload comments => post" do
254
+ Comment.find(:all).each do |comment|
255
+ comment.post.name
256
+ end
257
+ Bullet::Association.check_unused_preload_associations
258
+ Bullet::Association.should_not be_has_unused_preload_associations
259
+ end
260
+
261
+ it "should dectect no unused preload comments => post" do
262
+ Comment.find(:all, :include => :post).each do |comment|
263
+ comment.post.name
264
+ end
265
+ Bullet::Association.check_unused_preload_associations
266
+ Bullet::Association.should_not be_has_unused_preload_associations
267
+ end
268
+ end
269
+ end
270
+
271
+ describe Bullet::Association, 'has_and_belongs_to_many' do
272
+ def setup_db
273
+ ActiveRecord::Schema.define(:version => 1) do
274
+ create_table :students do |t|
275
+ t.column :name, :string
276
+ end
277
+
278
+ create_table :teachers do |t|
279
+ t.column :name, :string
280
+ end
281
+
282
+ create_table :students_teachers, :id => false do |t|
283
+ t.column :student_id, :integer
284
+ t.column :teacher_id, :integer
285
+ end
286
+ end
287
+ end
288
+
289
+ def teardown_db
290
+ ActiveRecord::Base.connection.tables.each do |table|
291
+ ActiveRecord::Base.connection.drop_table(table)
292
+ end
293
+ end
294
+
295
+ class Student < ActiveRecord::Base
296
+ has_and_belongs_to_many :teachers
297
+ end
298
+
299
+ class Teacher < ActiveRecord::Base
300
+ has_and_belongs_to_many :students
301
+ end
302
+
303
+ before(:all) do
304
+ setup_db
305
+ student1 = Student.create(:name => 'first')
306
+ student2 = Student.create(:name => 'second')
307
+ teacher1 = Teacher.create(:name => 'first')
308
+ teacher2 = Teacher.create(:name => 'second')
309
+ student1.teachers = [teacher1, teacher2]
310
+ student2.teachers = [teacher1, teacher2]
311
+ teacher1.students << student1
312
+ teacher2.students << student2
313
+ end
314
+
315
+ after(:all) do
316
+ teardown_db
317
+ end
318
+
319
+ before(:each) do
320
+ Bullet::Association.start_request
321
+ end
322
+
323
+ after(:each) do
324
+ Bullet::Association.end_request
325
+ end
326
+
327
+ it "should detect unpreload associatoins" do
328
+ Student.find(:all).each do |student|
329
+ student.teachers.collect(&:name)
330
+ end
331
+ Bullet::Association.should be_has_unpreload_associations
332
+ end
333
+
334
+ it "should detect no unpreload associatoins" do
335
+ Student.find(:all, :include => :teachers).each do |student|
336
+ student.teachers.collect(&:name)
337
+ end
338
+ Bullet::Association.should_not be_has_unpreload_associations
339
+ end
340
+
341
+ it "should detect unused preload associatoins" do
342
+ Student.find(:all, :include => :teachers).collect(&:name)
343
+ Bullet::Association.check_unused_preload_associations
344
+ Bullet::Association.should be_has_unused_preload_associations
345
+ end
346
+
347
+ it "should detect no unused preload associatoins" do
348
+ Student.find(:all).collect(&:name)
349
+ Bullet::Association.check_unused_preload_associations
350
+ Bullet::Association.should_not be_has_unused_preload_associations
351
+ end
352
+ end
353
+
354
+ describe Bullet::Association, 'has_many :through' do
355
+ def setup_db
356
+ ActiveRecord::Schema.define(:version => 1) do
357
+ create_table :firms do |t|
358
+ t.column :name, :string
359
+ end
360
+
361
+ create_table :clients do |t|
362
+ t.column :name, :string
363
+ end
364
+
365
+ create_table :relations do |t|
366
+ t.column :firm_id, :integer
367
+ t.column :client_id, :integer
368
+ end
369
+ end
370
+ end
371
+
372
+ def teardown_db
373
+ ActiveRecord::Base.connection.tables.each do |table|
374
+ ActiveRecord::Base.connection.drop_table(table)
375
+ end
376
+ end
377
+
378
+ class Firm < ActiveRecord::Base
379
+ has_many :relations
380
+ has_many :clients, :through => :relations
381
+ end
382
+
383
+ class Client < ActiveRecord::Base
384
+ has_many :relations
385
+ has_many :firms, :through => :relations
386
+ end
387
+
388
+ class Relation < ActiveRecord::Base
389
+ belongs_to :firm
390
+ belongs_to :client
391
+ end
392
+
393
+ before(:all) do
394
+ setup_db
395
+ firm1 = Firm.create(:name => 'first')
396
+ firm2 = Firm.create(:name => 'second')
397
+ client1 = Client.create(:name => 'first')
398
+ client2 = Client.create(:name => 'second')
399
+ firm1.clients = [client1, client2]
400
+ firm2.clients = [client1, client2]
401
+ client1.firms << firm1
402
+ client2.firms << firm2
403
+ end
404
+
405
+ after(:all) do
406
+ teardown_db
407
+ end
408
+
409
+ before(:each) do
410
+ Bullet::Association.start_request
411
+ end
412
+
413
+ after(:each) do
414
+ Bullet::Association.end_request
415
+ end
416
+
417
+ it "should detect unpreload associatoins" do
418
+ Firm.find(:all).each do |firm|
419
+ firm.clients.collect(&:name)
420
+ end
421
+ Bullet::Association.should be_has_unpreload_associations
422
+ end
423
+
424
+ it "should detect no unpreload associatoins" do
425
+ Firm.find(:all, :include => :clients).each do |firm|
426
+ firm.clients.collect(&:name)
427
+ end
428
+ Bullet::Association.should_not be_has_unpreload_associations
429
+ end
430
+
431
+ it "should detect no unused preload associatoins" do
432
+ Firm.find(:all).collect(&:name)
433
+ Bullet::Association.check_unused_preload_associations
434
+ Bullet::Association.should_not be_has_unused_preload_associations
435
+ end
436
+
437
+ it "should detect unused preload associatoins" do
438
+ Firm.find(:all, :include => :clients).collect(&:name)
439
+ Bullet::Association.check_unused_preload_associations
440
+ Bullet::Association.should be_has_unused_preload_associations
441
+ end
442
+ end
443
+
444
+ describe Bullet::Association, 'has_many :as' do
445
+ def setup_db
446
+ ActiveRecord::Schema.define(:version => 1) do
447
+ create_table :votes do |t|
448
+ t.column :vote, :integer
449
+ t.references :voteable, :polymorphic => true
450
+ end
451
+
452
+ create_table :users do |t|
453
+ t.column :name, :string
454
+ end
455
+
456
+ create_table :news do |t|
457
+ t.column :name, :string
458
+ end
459
+ end
460
+ end
461
+
462
+ def teardown_db
463
+ ActiveRecord::Base.connection.tables.each do |table|
464
+ ActiveRecord::Base.connection.drop_table(table)
465
+ end
466
+ end
467
+
468
+ class Vote < ActiveRecord::Base
469
+ belongs_to :voteable, :polymorphic => true
470
+ end
471
+
472
+ class User < ActiveRecord::Base
473
+ has_many :votes, :as => :voteable
474
+ end
475
+
476
+ class News < ActiveRecord::Base
477
+ has_many :votes, :as => :voteable
478
+ end
479
+
480
+ before(:all) do
481
+ setup_db
482
+ user1 = User.create(:name => 'first')
483
+ user2 = User.create(:name => 'second')
484
+ user1.votes << Vote.create(:vote => 10)
485
+ user1.votes << Vote.create(:vote => 20)
486
+ user2.votes << Vote.create(:vote => 10)
487
+ user2.votes << Vote.create(:vote => 20)
488
+
489
+ news1 = News.create(:name => 'first')
490
+ news2 = News.create(:name => 'second')
491
+ news1.votes << Vote.create(:vote => 10)
492
+ news1.votes << Vote.create(:vote => 20)
493
+ news2.votes << Vote.create(:vote => 10)
494
+ news2.votes << Vote.create(:vote => 20)
495
+ end
496
+
497
+ after(:all) do
498
+ teardown_db
499
+ end
500
+
501
+ before(:each) do
502
+ Bullet::Association.start_request
503
+ end
504
+
505
+ after(:each) do
506
+ Bullet::Association.end_request
507
+ end
508
+
509
+ it "should detect unpreload associatoins" do
510
+ User.find(:all).each do |user|
511
+ user.votes.collect(&:vote)
512
+ end
513
+ Bullet::Association.should be_has_unpreload_associations
514
+ end
515
+
516
+ it "should detect no unpreload associatoins" do
517
+ User.find(:all, :include => :votes).each do |user|
518
+ user.votes.collect(&:vote)
519
+ end
520
+ Bullet::Association.should_not be_has_unpreload_associations
521
+ end
522
+
523
+ it "should detect unpreload associatoins with voteable" do
524
+ Vote.find(:all).each do |vote|
525
+ vote.voteable.name
526
+ end
527
+ Bullet::Association.should be_has_unpreload_associations
528
+ end
529
+
530
+ it "should detect no unpreload associatoins with voteable" do
531
+ Vote.find(:all, :include => :voteable).each do |vote|
532
+ vote.voteable.name
533
+ end
534
+ Bullet::Association.should_not be_has_unpreload_associations
535
+ end
536
+
537
+ it "should detect no unused preload associations" do
538
+ User.find(:all).collect(&:name)
539
+ Bullet::Association.check_unused_preload_associations
540
+ Bullet::Association.should_not be_has_unused_preload_associations
541
+ end
542
+
543
+ it "should detect unused preload associations" do
544
+ User.find(:all, :include => :votes).collect(&:name)
545
+ Bullet::Association.check_unused_preload_associations
546
+ Bullet::Association.should be_has_unused_preload_associations
547
+ end
548
+
549
+ it "should detect no unused preload associations with voteable" do
550
+ Vote.find(:all).collect(&:vote)
551
+ Bullet::Association.check_unused_preload_associations
552
+ Bullet::Association.should_not be_has_unused_preload_associations
553
+ end
554
+
555
+ it "should detect unused preload associatoins with voteable" do
556
+ Vote.find(:all, :include => :voteable).collect(&:vote)
557
+ Bullet::Association.check_unused_preload_associations
558
+ Bullet::Association.should be_has_unused_preload_associations
559
+ end
560
+ end
561
+
562
+ describe Bullet::Association, "has_one" do
563
+ def setup_db
564
+ ActiveRecord::Schema.define(:version => 1) do
565
+ create_table :companies do |t|
566
+ t.column :name, :string
567
+ end
568
+
569
+ create_table :addresses do |t|
570
+ t.column :name, :string
571
+ t.column :company_id, :integer
572
+ end
573
+ end
574
+ end
575
+
576
+ def teardown_db
577
+ ActiveRecord::Base.connection.tables.each do |table|
578
+ ActiveRecord::Base.connection.drop_table(table)
579
+ end
580
+ end
581
+
582
+ class Company < ActiveRecord::Base
583
+ has_one :address
584
+ end
585
+
586
+ class Address < ActiveRecord::Base
587
+ belongs_to :company
588
+ end
589
+
590
+ before(:all) do
591
+ setup_db
592
+
593
+ company1 = Company.create(:name => 'first')
594
+ company2 = Company.create(:name => 'second')
595
+
596
+ Address.create(:name => 'first', :company => company1)
597
+ Address.create(:name => 'second', :company => company2)
598
+ end
599
+
600
+ after(:all) do
601
+ teardown_db
602
+ end
603
+
604
+ before(:each) do
605
+ Bullet::Association.start_request
606
+ end
607
+
608
+ after(:each) do
609
+ Bullet::Association.end_request
610
+ end
611
+
612
+ it "should detect unpreload association" do
613
+ Company.find(:all).each do |company|
614
+ company.address.name
615
+ end
616
+ Bullet::Association.should be_has_unpreload_associations
617
+ end
618
+
619
+ it "should detect no unpreload association" do
620
+ Company.find(:all, :include => :address).each do |company|
621
+ company.address.name
622
+ end
623
+ Bullet::Association.should_not be_has_unpreload_associations
624
+ end
625
+
626
+ it "should detect no unused preload association" do
627
+ Company.find(:all).collect(&:name)
628
+ Bullet::Association.check_unused_preload_associations
629
+ Bullet::Association.should_not be_has_unused_preload_associations
630
+ end
631
+
632
+ it "should detect unused preload association" do
633
+ Company.find(:all, :include => :address).collect(&:name)
634
+ Bullet::Association.check_unused_preload_associations
635
+ Bullet::Association.should be_has_unused_preload_associations
636
+ end
637
+ end
638
+
639
+ describe Bullet::Association, "call one association that in possiable objects" do
640
+ def setup_db
641
+ ActiveRecord::Schema.define(:version => 1) do
642
+ create_table :contacts do |t|
643
+ t.column :name, :string
644
+ end
645
+
646
+ create_table :emails do |t|
647
+ t.column :name, :string
648
+ t.column :contact_id, :integer
649
+ end
650
+ end
651
+ end
652
+
653
+ def teardown_db
654
+ ActiveRecord::Base.connection.tables.each do |table|
655
+ ActiveRecord::Base.connection.drop_table(table)
656
+ end
657
+ end
658
+
659
+ class Contact < ActiveRecord::Base
660
+ has_many :emails
661
+ end
662
+
663
+ class Email < ActiveRecord::Base
664
+ belongs_to :contact
665
+ end
666
+
667
+ before(:all) do
668
+ setup_db
669
+
670
+ contact1 = Contact.create(:name => 'first')
671
+ contact2 = Contact.create(:name => 'second')
672
+
673
+ email1 = contact1.emails.create(:name => 'first')
674
+ email2 = contact1.emails.create(:name => 'second')
675
+ email3 = contact2.emails.create(:name => 'third')
676
+ email4 = contact2.emails.create(:name => 'fourth')
677
+ end
678
+
679
+ after(:all) do
680
+ teardown_db
681
+ end
682
+
683
+ before(:each) do
684
+ Bullet::Association.start_request
685
+ end
686
+
687
+ after(:each) do
688
+ Bullet::Association.end_request
689
+ end
690
+
691
+ it "should detect no unpreload association" do
692
+ Contact.find(:all)
693
+ Contact.first.emails.collect(&:name)
694
+ Bullet::Association.should_not be_has_unpreload_associations
695
+ end
696
+ end