require 'spec_helper' module Bullet module Detector describe NPlusOneQuery do before(:all) do @post = Post.first @post2 = Post.last end context ".call_association" do it "should add call_object_associations" do expect(NPlusOneQuery).to receive(:add_call_object_associations).with(@post, :associations) NPlusOneQuery.call_association(@post, :associations) end end context ".possible?" do it "should be true if possible_objects contain" do NPlusOneQuery.add_possible_objects(@post) expect(NPlusOneQuery.possible?(@post)).to eq true end end context ".impossible?" do it "should be true if impossible_objects contain" do NPlusOneQuery.add_impossible_object(@post) expect(NPlusOneQuery.impossible?(@post)).to eq true end end context ".association?" do it "should be true if object, associations pair is already existed" do NPlusOneQuery.add_object_associations(@post, :association) expect(NPlusOneQuery.association?(@post, :association)).to eq true end it "should be false if object, association pair is not existed" do NPlusOneQuery.add_object_associations(@post, :association1) expect(NPlusOneQuery.association?(@post, :associatio2)).to eq false end end context ".conditions_met?" do it "should be true if object is possible, not impossible and object, associations pair is not already existed" do allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true) allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false) allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false) expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq true end it "should be false if object is not possible, not impossible and object, associations pair is not already existed" do allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(false) allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false) allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false) expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false end it "should be false if object is possible, but impossible and object, associations pair is not already existed" do allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true) allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(true) allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(false) expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false end it "should be false if object is possible, not impossible and object, associations pair is already existed" do allow(NPlusOneQuery).to receive(:possible?).with(@post).and_return(true) allow(NPlusOneQuery).to receive(:impossible?).with(@post).and_return(false) allow(NPlusOneQuery).to receive(:association?).with(@post, :associations).and_return(true) expect(NPlusOneQuery.conditions_met?(@post, :associations)).to eq false end end context ".call_association" do it "should create notification if conditions met" do expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true) expect(NPlusOneQuery).to receive(:caller_in_project).and_return(["caller"]) expect(NPlusOneQuery).to receive(:create_notification).with(["caller"], "Post", :association) NPlusOneQuery.call_association(@post, :association) end it "should not create notification if conditions not met" do expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(false) expect(NPlusOneQuery).not_to receive(:caller_in_project!) expect(NPlusOneQuery).not_to receive(:create_notification).with("Post", :association) NPlusOneQuery.call_association(@post, :association) end context "stacktrace_excludes" do before { Bullet.stacktrace_excludes = [ /def/ ] } after { Bullet.stacktrace_excludes = nil } it "should not create notification when stacktrace contains paths that are in the exclude list" do in_project = File.join(Dir.pwd, 'abc', 'abc.rb') included_path = '/ghi/ghi.rb' excluded_path = '/def/def.rb' expect(NPlusOneQuery).to receive(:caller).and_return([in_project, included_path, excluded_path]) expect(NPlusOneQuery).to_not receive(:create_notification) NPlusOneQuery.call_association(@post, :association) end end end context ".caller_in_project" do it "should include only paths that are in the project" do in_project = File.join(Dir.pwd, 'abc', 'abc.rb') not_in_project = '/def/def.rb' expect(NPlusOneQuery).to receive(:caller).and_return([in_project, not_in_project]) expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true) expect(NPlusOneQuery).to receive(:create_notification).with([in_project], "Post", :association) NPlusOneQuery.call_association(@post, :association) end context "stacktrace_includes" do before { Bullet.stacktrace_includes = [ 'def', /xyz/ ] } after { Bullet.stacktrace_includes = nil } it "should include paths that are in the stacktrace_include list" do in_project = File.join(Dir.pwd, 'abc', 'abc.rb') included_gems = ['/def/def.rb', 'xyz/xyz.rb'] excluded_gem = '/ghi/ghi.rb' expect(NPlusOneQuery).to receive(:caller).and_return([in_project, *included_gems, excluded_gem]) expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true) expect(NPlusOneQuery).to receive(:create_notification).with([in_project, *included_gems], "Post", :association) NPlusOneQuery.call_association(@post, :association) end end end context ".add_possible_objects" do it "should add possible objects" do NPlusOneQuery.add_possible_objects([@post, @post2]) expect(NPlusOneQuery.possible_objects).to be_include(@post.bullet_key) expect(NPlusOneQuery.possible_objects).to be_include(@post2.bullet_key) end it "should not raise error if object is nil" do expect { NPlusOneQuery.add_possible_objects(nil) }.not_to raise_error end end context ".add_impossible_object" do it "should add impossible object" do NPlusOneQuery.add_impossible_object(@post) expect(NPlusOneQuery.impossible_objects).to be_include(@post.bullet_key) end end end end end