require "spec_helper" require "ostruct" class TestStore < ActionDispatch::Session::MongoStoreBase class Session < OpenStruct def self.where(_ = {}) [] end end end describe ActionDispatch::Session::MongoStoreBase do let(:session_options_key) { described_class::ENV_SESSION_OPTIONS_KEY } describe ".session_class" do let(:store_class) { TestStore } let(:store) { store_class.new(nil) } subject { store_class.session_class } it "returns child session class" do expect(subject).to eq(TestStore::Session) end end describe "#get_session" do let(:env) { {} } let(:store_class) { TestStore } let(:store) { store_class.new(nil) } let(:session_class) { store_class::Session } let(:session_record) { env[store_class::SESSION_RECORD_KEY] } context "when no session exists" do it "creates a new session" do sid, session_data = store.send(:get_session, env, nil) expect(sid).to be_kind_of(String) expect(session_data).to be_nil expect(session_record).to be_kind_of(session_class) expect(session_record._id).to eq sid env_record = env[described_class::SESSION_RECORD_KEY] expect(env_record).to be_kind_of(session_class) expect(env_record._id).to eq sid end end context "when given session is found" do let(:session) { session_class.new(:_id => "foo", :data => nil) } before do expect(session_class).to receive(:where).and_return([session]) end it "returns the existing session" do sid, session_data = store.send(:get_session, env, session._id) expect(sid).to eq(session._id) expect(sid).to be_kind_of(String) expect(session_data).to be_nil expect(session_record).to be_kind_of(session_class) expect(session_record._id).to eq sid env_record = env[described_class::SESSION_RECORD_KEY] expect(env_record).to be_kind_of(session_class) expect(env_record._id).to eq sid end end context "when given session is not found" do let(:not_existing_session_id) { SecureRandom.hex } it "creates a new session" do sid, session_data = store.send(:get_session, env, not_existing_session_id) expect(sid).to_not eq(not_existing_session_id) expect(sid).to be_kind_of(String) expect(session_data).to be_nil expect(session_record).to be_kind_of(session_class) expect(session_record._id).to eq sid env_record = env[described_class::SESSION_RECORD_KEY] expect(env_record).to be_kind_of(session_class) expect(env_record._id).to eq sid end end context "with custom session class" do let(:store_class) { TestStore } it "returns a session record from the custom session class" do sid, session_data = store.send(:get_session, env, nil) expect(sid).to be_kind_of(String) expect(session_data).to be_nil expect(session_record).to be_kind_of(session_class) expect(session_record._id.to_s).to eq sid end end end describe "#set_session" do let(:store_class) { mongo_orm == "mongoid" ? MongoidStore : MongoStore } let(:store) { store_class.new(nil) } let(:session_class) { store_class::Session } subject { store.send(:set_session, env, generate_sid, {}) } context "with existing session record" do let(:id) { generate_sid } let!(:session_record) { session_class.new(:_id => id).tap(&:save) } let(:env) do { "rack.session" => double(:id => id), session_options_key => { :id => id } } end subject { store.send(:set_session, env, id, {}) } it "uses the existing record" do expect do subject end.to_not change { session_class.collection.find(:_id => id).count } expect(subject).to eq(id.to_s) end it "yields" do yielded_variable = :not_called block = proc do yielded_variable = :called end store.send(:set_session, env, id, {}, &block) expect(yielded_variable).to eq(:called) end context "with session record in the ENV" do let(:env) do { "rack.session" => double(:id => id), session_options_key => { :id => id }, "rack.session.record" => session_record } end it "uses the record from the ENV" do expect do expect(session_record).to receive(:data=).and_call_original subject end.to_not change { session_class.collection.find(:_id => id).count } end end end context "without existing session record" do let :env do { "rack.session" => {}, session_options_key => {} } end it "creates a session record" do expect do subject end.to change { session_class.collection.find.count }.from(0).to(1) expect(subject).to be_kind_of(String) end it "sets the session record in the env" do sid = subject expect(env["rack.session.record"]).to be_kind_of(session_class) expect(env["rack.session.record"]._id.to_s).to eq(sid) end context "when not saved" do before do record = double("data=" => nil, :save => false) expect(store).to receive(:get_session_record).and_return([1, record]) end it "returns false" do expect(subject).to be false end end end end describe "#destroy_session" do let(:id) { generate_sid } let(:store_class) { mongo_orm == "mongoid" ? MongoidStore : MongoStore } let(:store) { store_class.new(nil) } let(:session_class) { store_class::Session } let(:env) do { "rack.session" => double(:id => id), session_options_key => {} } end context "without existing session" do subject { store.send(:destroy_session, env, id, {}) } it "does not remove any record" do expect { subject }.to_not change { session_class.collection.count } end it "returns new session id" do expect(subject).to be_kind_of(String) expect(subject).to_not eq(id) end context "with option :drop" do subject { store.send(:destroy_session, env, id, :drop => true) } it "does not remove any record" do expect { subject }.to_not change { session_class.collection.count } end it "returns nothing" do expect(subject).to be_nil end end end context "with existing session" do let!(:session_record) { session_class.new(:_id => id).tap(&:save) } subject { store.send(:destroy_session, env, id, {}) } it "removes the session record" do expect do subject end.to change { session_class.collection.find(:_id => id).count }.from(1).to(0) end it "returns new session id" do expect(subject).to be_kind_of(String) expect(subject).to_not eq(session_record._id) end context "with session record in the ENV" do let(:env) do { "rack.session" => double(:id => id), session_options_key => { :id => id }, "rack.session.record" => session_record } end subject { store.send(:destroy_session, env, id, :drop => true) } it "destroys record in the env" do expect do expect(session_record).to receive(:destroy).and_call_original subject end.to change { session_class.collection.find(:_id => id).count }.from(1).to(0) end end context "with option :drop" do subject { store.send(:destroy_session, env, id, :drop => true) } it "removes the session record" do expect do subject end.to change { session_class.collection.find(:_id => id).count }.from(1).to(0) end it "returns nothing" do expect(subject).to be_nil end end end end end