flipsasser-bullet 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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