Commit 229fd8af authored by nmilojevic1's avatar nmilojevic1

Add specs for both SharedState and Sessions store

parent e6551492
......@@ -45,22 +45,26 @@ RSpec.describe Groups::DependencyProxyForContainersController do
expect(response).to have_gitlab_http_status(:not_found)
end
context 'with an active session', :clean_gitlab_redis_shared_state do
let(:session_id) { '42' }
let(:session_time) { 5.minutes.ago }
let(:stored_session) do
{ 'active_group_sso_sign_ins' => { saml_provider.id => session_time } }
end
shared_examples 'active session' do
context 'with an active session' do
let(:session_id) { '42' }
let(:session_time) { 5.minutes.ago }
let(:stored_session) do
{ 'active_group_sso_sign_ins' => { saml_provider.id => session_time } }
end
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
end
end
end
it_behaves_like successful_example
it_behaves_like successful_example
end
end
it_behaves_like 'redis sessions store', 'active session'
end
context 'when git check is not enforced' do
......
......@@ -85,44 +85,52 @@ RSpec.describe 'Login' do
expect(page.body).to have_link('Register now', href: new_user_registration_path)
end
describe 'with two-factor authentication required', :clean_gitlab_redis_shared_state do
let_it_be(:user) { create(:user) }
let_it_be(:smartcard_identity) { create(:smartcard_identity, user: user) }
RSpec.shared_examples_for 'two-factor authentication' do
before do
stub_application_setting(require_two_factor_authentication: true)
load Rails.root.join('config/initializers/session_store.rb')
end
context 'with a smartcard session' do
let(:openssl_certificate_store) { instance_double(OpenSSL::X509::Store) }
let(:openssl_certificate) do
instance_double(OpenSSL::X509::Certificate, subject: smartcard_identity.subject, issuer: smartcard_identity.issuer)
describe 'with two-factor authentication required' do
let_it_be(:user) { create(:user) }
let_it_be(:smartcard_identity) { create(:smartcard_identity, user: user) }
before do
stub_application_setting(require_two_factor_authentication: true)
end
it 'does not ask for Two-Factor Authentication' do
allow(Gitlab::Auth::Smartcard::Certificate).to receive(:store).and_return(openssl_certificate_store)
allow(OpenSSL::X509::Certificate).to receive(:new).and_return(openssl_certificate)
allow(openssl_certificate_store).to receive(:verify).and_return(true)
context 'with a smartcard session' do
let(:openssl_certificate_store) { instance_double(OpenSSL::X509::Store) }
let(:openssl_certificate) do
instance_double(OpenSSL::X509::Certificate, subject: smartcard_identity.subject, issuer: smartcard_identity.issuer)
end
it 'does not ask for Two-Factor Authentication' do
allow(Gitlab::Auth::Smartcard::Certificate).to receive(:store).and_return(openssl_certificate_store)
allow(OpenSSL::X509::Certificate).to receive(:new).and_return(openssl_certificate)
allow(openssl_certificate_store).to receive(:verify).and_return(true)
# Loging using smartcard
visit verify_certificate_smartcard_path(client_certificate: openssl_certificate)
# Loging using smartcard
visit verify_certificate_smartcard_path(client_certificate: openssl_certificate)
visit profile_path
visit profile_path
expect(page).not_to have_content('Two-Factor Authentication')
expect(page).not_to have_content('Two-Factor Authentication')
end
end
end
context 'without a smartcard session' do
it 'asks for Two-Factor Authentication' do
sign_in(user)
context 'without a smartcard session' do
it 'asks for Two-Factor Authentication' do
sign_in(user)
visit profile_path
visit profile_path
expect(page).to have_content('Two-Factor Authentication')
expect(page).to have_content('Two-Factor Authentication')
end
end
end
end
it_behaves_like 'redis sessions store', 'two-factor authentication'
end
end
end
......
......@@ -2,62 +2,66 @@
require 'spec_helper'
RSpec.describe Gitlab::Auth::Otp::SessionEnforcer, :clean_gitlab_redis_shared_state do
let_it_be(:key) { create(:key)}
RSpec.describe Gitlab::Auth::Otp::SessionEnforcer do
shared_examples_for 'otp session enforcer' do
let_it_be(:key) { create(:key)}
describe '#update_session' do
let(:redis) { double(:redis) }
describe '#update_session' do
let(:redis) { double(:redis) }
before do
stub_licensed_features(git_two_factor_enforcement: true)
end
it 'registers a session in Redis' do
expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis)
session_expiry_in_seconds = Gitlab::CurrentSettings.git_two_factor_session_expiry.minutes.to_i
expect(redis).to(
receive(:setex)
.with("#{described_class::OTP_SESSIONS_NAMESPACE}:#{key.id}",
session_expiry_in_seconds,
true)
.once)
described_class.new(key).update_session
end
context 'when licensed feature is not available' do
before do
stub_licensed_features(git_two_factor_enforcement: false)
stub_licensed_features(git_two_factor_enforcement: true)
end
it 'does not register a session in Redis' do
expect(redis).not_to receive(:setex)
it 'registers a session in Redis' do
expect(redis_store_class).to receive(:with).and_yield(redis)
session_expiry_in_seconds = Gitlab::CurrentSettings.git_two_factor_session_expiry.minutes.to_i
expect(redis).to(
receive(:setex)
.with("#{::Gitlab::Redis::Sessions::OTP_SESSIONS_NAMESPACE}:#{key.id}",
session_expiry_in_seconds,
true)
.once)
described_class.new(key).update_session
end
end
end
describe '#access_restricted?' do
subject { described_class.new(key).access_restricted? }
context 'when licensed feature is not available' do
before do
stub_licensed_features(git_two_factor_enforcement: false)
end
it 'does not register a session in Redis' do
expect(redis).not_to receive(:setex)
before do
stub_licensed_features(git_two_factor_enforcement: true)
described_class.new(key).update_session
end
end
end
context 'with existing session' do
describe '#access_restricted?' do
subject { described_class.new(key).access_restricted? }
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("#{described_class::OTP_SESSIONS_NAMESPACE}:#{key.id}", true )
end
stub_licensed_features(git_two_factor_enforcement: true)
end
it { is_expected.to be_falsey }
end
context 'with existing session' do
before do
redis_store_class.with do |redis|
redis.set("#{::Gitlab::Redis::Sessions::OTP_SESSIONS_NAMESPACE}:#{key.id}", true )
end
end
it { is_expected.to be_falsey }
end
context 'without an existing session' do
it { is_expected.to be_truthy }
context 'without an existing session' do
it { is_expected.to be_truthy }
end
end
end
it_behaves_like 'redis sessions store', 'otp session enforcer'
end
......@@ -29,22 +29,26 @@ RSpec.describe Gitlab::Auth::Smartcard::SessionEnforcer do
stub_smartcard_setting(enabled: true, required_for_git_access: true)
end
context 'with a smartcard session', :clean_gitlab_redis_shared_state do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
RSpec.shared_examples_for 'smartcard session' do
context 'with a smartcard session' do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
end
end
end
it { is_expected.to be_falsey }
it { is_expected.to be_falsey }
end
end
it_behaves_like 'redis sessions store', 'smartcard session'
context 'without any session' do
it { is_expected.to be_truthy }
end
......
......@@ -3,45 +3,49 @@
require 'spec_helper'
RSpec.describe Gitlab::Auth::Smartcard::Session do
describe '#active?' do
let(:user) { create(:user) }
RSpec.shared_examples_for 'smartcard session' do
describe '#active?' do
let(:user) { create(:user) }
subject { described_class.new.active?(user) }
subject { described_class.new.active?(user) }
context 'with a smartcard session', :clean_gitlab_redis_shared_state do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
context 'with a smartcard session' do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
end
end
it { is_expected.to be_truthy }
end
it { is_expected.to be_truthy }
context 'without any session' do
it { is_expected.to be_falsey }
end
end
context 'without any session' do
it { is_expected.to be_falsey }
end
end
describe '#update_active' do
let(:now) { Time.now }
describe '#update_active' do
let(:now) { Time.now }
around do |example|
Gitlab::Session.with_session({}) do
example.run
around do |example|
Gitlab::Session.with_session({}) do
example.run
end
end
end
it 'stores the time of last sign-in' do
subject.update_active(now)
it 'stores the time of last sign-in' do
subject.update_active(now)
expect(Gitlab::Session.current[:smartcard_signins]).to eq({ 'last_signin_at' => now })
expect(Gitlab::Session.current[:smartcard_signins]).to eq({ 'last_signin_at' => now })
end
end
end
it_behaves_like 'redis sessions store', 'smartcard session'
end
This diff is collapsed.
......@@ -154,26 +154,30 @@ RSpec.describe API::Internal::Base do
project.add_developer(user)
end
context 'user with a smartcard session', :clean_gitlab_redis_shared_state do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
RSpec.shared_examples_for 'smartcard session' do
context 'user with a smartcard session' do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
end
end
end
it "allows access" do
subject
it "allows access" do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to have_gitlab_http_status(:ok)
end
end
end
it_behaves_like 'redis sessions store', 'smartcard session'
context 'user without a smartcard session' do
it "does not allow access" do
subject
......
......@@ -54,26 +54,30 @@ RSpec.describe Repositories::GitHttpController, type: :request do
project.add_developer(user)
end
context 'user with a smartcard session', :clean_gitlab_redis_shared_state do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
RSpec.shared_examples_for 'smartcard session' do
context 'user with a smartcard session' do
let(:session_id) { '42' }
let(:stored_session) do
{ 'smartcard_signins' => { 'last_signin_at' => 5.minutes.ago } }
end
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id}", Marshal.dump(stored_session))
redis.sadd("session:lookup:user:gitlab:#{user.id}", [session_id])
end
end
end
it "allows access" do
subject
it "allows access" do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to have_gitlab_http_status(:ok)
end
end
end
it_behaves_like 'redis sessions store', 'smartcard session'
context 'user without a smartcard session' do
it "does not allow access" do
subject
......
......@@ -2,31 +2,43 @@
require 'spec_helper'
RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_shared_state do
let(:session_id) { Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') }
RSpec.describe ApplicationCable::Connection do
RSpec.shared_examples_for 'ApplicationCable::Connection' do
let(:session_id) { Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') }
context 'when session cookie is set' do
before do
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
end
context 'when session cookie is set' do
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
end
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
end
context 'when user is logged in' do
let(:user) { create(:user) }
let(:session_hash) { { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] } }
context 'when user is logged in' do
let(:user) { create(:user) }
let(:session_hash) { { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] } }
it 'sets current_user' do
connect
it 'sets current_user' do
connect
expect(connection.current_user).to eq(user)
end
expect(connection.current_user).to eq(user)
context 'with a stale password' do
let(:partial_password_hash) { build(:user, password: 'some_old_password').encrypted_password[0, 29] }
let(:session_hash) { { 'warden.user.user.key' => [[user.id], partial_password_hash] } }
it 'sets current_user to nil' do
connect
expect(connection.current_user).to be_nil
end
end
end
context 'with a stale password' do
let(:partial_password_hash) { build(:user, password: 'some_old_password').encrypted_password[0, 29] }
let(:session_hash) { { 'warden.user.user.key' => [[user.id], partial_password_hash] } }
context 'when user is not logged in' do
let(:session_hash) { {} }
it 'sets current_user to nil' do
connect
......@@ -36,32 +48,24 @@ RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_shared_state do
end
end
context 'when user is not logged in' do
let(:session_hash) { {} }
context 'when session cookie is not set' do
it 'sets current_user to nil' do
connect
expect(connection.current_user).to be_nil
end
end
end
context 'when session cookie is not set' do
it 'sets current_user to nil' do
connect
expect(connection.current_user).to be_nil
end
end
context 'when session cookie is an empty string' do
it 'sets current_user to nil' do
cookies[Gitlab::Application.config.session_options[:key]] = ''
context 'when session cookie is an empty string' do
it 'sets current_user to nil' do
cookies[Gitlab::Application.config.session_options[:key]] = ''
connect
connect
expect(connection.current_user).to be_nil
expect(connection.current_user).to be_nil
end
end
end
it_behaves_like 'redis sessions store', 'ApplicationCable::Connection'
end
......@@ -2,70 +2,74 @@
require 'spec_helper'
RSpec.describe 'Active user sessions', :clean_gitlab_redis_shared_state do
it 'successful login adds a new active user login' do
now = Time.zone.parse('2018-03-12 09:06')
Timecop.freeze(now) do
user = create(:user)
gitlab_sign_in(user)
expect(current_path).to eq root_path
sessions = ActiveSession.list(user)
expect(sessions.count).to eq 1
# refresh the current page updates the updated_at
Timecop.freeze(now + 1.minute) do
visit current_path
RSpec.describe 'Active user sessions' do
RSpec.shared_examples_for 'active user sessions' do
it 'successful login adds a new active user login' do
now = Time.zone.parse('2018-03-12 09:06')
Timecop.freeze(now) do
user = create(:user)
gitlab_sign_in(user)
expect(current_path).to eq root_path
sessions = ActiveSession.list(user)
expect(sessions.first).to have_attributes(
created_at: Time.zone.parse('2018-03-12 09:06'),
updated_at: Time.zone.parse('2018-03-12 09:07')
)
expect(sessions.count).to eq 1
# refresh the current page updates the updated_at
Timecop.freeze(now + 1.minute) do
visit current_path
sessions = ActiveSession.list(user)
expect(sessions.first).to have_attributes(
created_at: Time.zone.parse('2018-03-12 09:06'),
updated_at: Time.zone.parse('2018-03-12 09:07')
)
end
end
end
end
it 'successful login cleans up obsolete entries' do
user = create(:user)
it 'successful login cleans up obsolete entries' do
user = create(:user)
Gitlab::Redis::SharedState.with do |redis|
redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
redis_store_class.with do |redis|
redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
gitlab_sign_in(user)
gitlab_sign_in(user)
Gitlab::Redis::SharedState.with do |redis|
expect(redis.smembers("session:lookup:user:gitlab:#{user.id}")).not_to include '59822c7d9fcdfa03725eff41782ad97d'
redis_store_class.with do |redis|
expect(redis.smembers("session:lookup:user:gitlab:#{user.id}")).not_to include '59822c7d9fcdfa03725eff41782ad97d'
end
end
end
it 'sessionless login does not clean up obsolete entries' do
user = create(:user)
personal_access_token = create(:personal_access_token, user: user)
it 'sessionless login does not clean up obsolete entries' do
user = create(:user)
personal_access_token = create(:personal_access_token, user: user)
Gitlab::Redis::SharedState.with do |redis|
redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
redis_store_class.with do |redis|
redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
visit user_path(user, :atom, private_token: personal_access_token.token)
expect(page.status_code).to eq 200
visit user_path(user, :atom, private_token: personal_access_token.token)
expect(page.status_code).to eq 200
Gitlab::Redis::SharedState.with do |redis|
expect(redis.smembers("session:lookup:user:gitlab:#{user.id}")).to include '59822c7d9fcdfa03725eff41782ad97d'
redis_store_class.with do |redis|
expect(redis.smembers("session:lookup:user:gitlab:#{user.id}")).to include '59822c7d9fcdfa03725eff41782ad97d'
end
end
end
it 'logout deletes the active user login' do
user = create(:user)
gitlab_sign_in(user)
expect(current_path).to eq root_path
it 'logout deletes the active user login' do
user = create(:user)
gitlab_sign_in(user)
expect(current_path).to eq root_path
expect(ActiveSession.list(user).count).to eq 1
expect(ActiveSession.list(user).count).to eq 1
gitlab_sign_out
expect(current_path).to eq new_user_session_path
gitlab_sign_out
expect(current_path).to eq new_user_session_path
expect(ActiveSession.list(user)).to be_empty
expect(ActiveSession.list(user)).to be_empty
end
end
it_behaves_like 'redis sessions store', 'active user sessions'
end
......@@ -2,38 +2,42 @@
require 'spec_helper'
RSpec.describe 'Session TTLs', :clean_gitlab_redis_shared_state do
RSpec.describe 'Session TTLs' do
include SessionHelpers
it 'creates a session with a short TTL when login fails' do
visit new_user_session_path
# The session key only gets created after a post
fill_in 'user_login', with: 'non-existant@gitlab.org'
fill_in 'user_password', with: '12345678'
click_button 'Sign in'
RSpec.shared_examples_for 'session ttls' do
it 'creates a session with a short TTL when login fails' do
visit new_user_session_path
# The session key only gets created after a post
fill_in 'user_login', with: 'non-existant@gitlab.org'
fill_in 'user_password', with: '12345678'
click_button 'Sign in'
expect(page).to have_content('Invalid login or password')
expect(page).to have_content('Invalid login or password')
expect_single_session_with_short_ttl
end
expect_single_session_with_short_ttl(redis_store_class)
end
it 'increases the TTL when the login succeeds' do
user = create(:user)
gitlab_sign_in(user)
it 'increases the TTL when the login succeeds' do
user = create(:user)
gitlab_sign_in(user)
expect(page).to have_content(user.name)
expect(page).to have_content(user.name)
expect_single_session_with_authenticated_ttl
end
expect_single_session_with_authenticated_ttl(redis_store_class)
end
context 'with an unauthorized project' do
let_it_be(:project) { create(:project, :repository) }
context 'with an unauthorized project' do
let_it_be(:project) { create(:project, :repository) }
it 'creates a session with a short TTL' do
visit project_raw_path(project, 'master/README.md')
it 'creates a session with a short TTL' do
visit project_raw_path(project, 'master/README.md')
expect_single_session_with_short_ttl
expect(page).to have_current_path(new_user_session_path)
expect_single_session_with_short_ttl(redis_store_class)
expect(page).to have_current_path(new_user_session_path)
end
end
end
it_behaves_like 'redis sessions store', 'session ttls'
end
This diff is collapsed.
......@@ -10,25 +10,37 @@ RSpec.describe 'Session initializer for GitLab' do
end
describe 'config#session_store' do
context 'when the GITLAB_REDIS_STORE_WITH_SESSION_STORE env is not set' do
context 'when the GITLAB_USE_REDIS_SESSIONS_STORE env is not set' do
before do
stub_env('GITLAB_REDIS_STORE_WITH_SESSION_STORE', nil)
stub_env('GITLAB_USE_REDIS_SESSIONS_STORE', nil)
end
it 'initialized as a redis_store with a proper Redis::Store instance' do
it 'initialized with Multistore as ENV var defaults to true' do
expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(redis_store: kind_of(::Redis::Store)))
load_session_store
end
end
context 'when the GITLAB_REDIS_STORE_WITH_SESSION_STORE env is disabled' do
context 'when the GITLAB_USE_REDIS_SESSIONS_STORE env is disabled' do
before do
stub_env('GITLAB_REDIS_STORE_WITH_SESSION_STORE', false)
stub_env('GITLAB_USE_REDIS_SESSIONS_STORE', false)
end
it 'initialized as a redis_store with a proper servers configuration' do
expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(servers: kind_of(Hash)))
expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(redis_store: kind_of(Redis::Store)))
load_session_store
end
end
context 'when the GITLAB_USE_REDIS_SESSIONS_STORE env is enabled' do
before do
stub_env('GITLAB_USE_REDIS_SESSIONS_STORE', true)
end
it 'initialized as a redis_store with a proper servers configuration' do
expect(subject).to receive(:session_store).with(:redis_store, a_hash_including(redis_store: kind_of(::Redis::Store)))
load_session_store
end
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do
RSpec.describe Gitlab::AnonymousSession do
let(:default_session_id) { '6919a6f1bb119dd7396fadc38fd18d0d' }
let(:additional_session_id) { '7919a6f1bb119dd7396fadc38fd18d0d' }
......@@ -12,56 +12,60 @@ RSpec.describe Gitlab::AnonymousSession, :clean_gitlab_redis_shared_state do
described_class.new('127.0.0.1')
end
describe '#store_session_ip' do
it 'adds session id to proper key' do
subject.count_session_ip
RSpec.shared_examples_for 'anonymous sessions' do
describe '#store_session_ip' do
it 'adds session id to proper key' do
subject.count_session_ip
Gitlab::Redis::SharedState.with do |redis|
expect(redis.get("session:lookup:ip:gitlab2:127.0.0.1").to_i).to eq 1
redis_store_class.with do |redis|
expect(redis.get("session:lookup:ip:gitlab2:127.0.0.1").to_i).to eq 1
end
end
end
it 'adds expiration time to key' do
freeze_time do
subject.count_session_ip
it 'adds expiration time to key' do
freeze_time do
subject.count_session_ip
Gitlab::Redis::SharedState.with do |redis|
expect(redis.ttl("session:lookup:ip:gitlab2:127.0.0.1")).to eq(24.hours.to_i)
redis_store_class.with do |redis|
expect(redis.ttl("session:lookup:ip:gitlab2:127.0.0.1")).to eq(24.hours.to_i)
end
end
end
end
context 'when there is already one session' do
it 'increments the session count' do
subject.count_session_ip
new_anonymous_session.count_session_ip
context 'when there is already one session' do
it 'increments the session count' do
subject.count_session_ip
new_anonymous_session.count_session_ip
Gitlab::Redis::SharedState.with do |redis|
expect(redis.get("session:lookup:ip:gitlab2:127.0.0.1").to_i).to eq(2)
redis_store_class.with do |redis|
expect(redis.get("session:lookup:ip:gitlab2:127.0.0.1").to_i).to eq(2)
end
end
end
end
end
describe '#stored_sessions' do
it 'returns all anonymous sessions per ip' do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:lookup:ip:gitlab2:127.0.0.1", 2)
end
describe '#stored_sessions' do
it 'returns all anonymous sessions per ip' do
redis_store_class.with do |redis|
redis.set("session:lookup:ip:gitlab2:127.0.0.1", 2)
end
expect(subject.session_count).to eq(2)
expect(subject.session_count).to eq(2)
end
end
end
it 'removes obsolete lookup through ip entries' do
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:lookup:ip:gitlab2:127.0.0.1", 2)
end
it 'removes obsolete lookup through ip entries' do
redis_store_class.with do |redis|
redis.set("session:lookup:ip:gitlab2:127.0.0.1", 2)
end
subject.cleanup_session_per_ip_count
subject.cleanup_session_per_ip_count
Gitlab::Redis::SharedState.with do |redis|
expect(redis.exists("session:lookup:ip:gitlab2:127.0.0.1")).to eq(false)
redis_store_class.with do |redis|
expect(redis.exists("session:lookup:ip:gitlab2:127.0.0.1")).to eq(false)
end
end
end
it_behaves_like 'redis sessions store', 'anonymous sessions'
end
......@@ -4,4 +4,54 @@ require 'spec_helper'
RSpec.describe Gitlab::Redis::Sessions do
include_examples "redis_new_instance_shared_examples", 'sessions', Gitlab::Redis::SharedState
describe 'redis instance used in connection pool' do
before do
clear_pool
end
context 'when redis.sessions configuration is not provided' do
it 'uses ::Redis instance' do
expect(described_class).to receive(:config_fallback?).and_return(true)
described_class.pool.with do |redis_instance|
expect(redis_instance).to be_instance_of(::Redis)
end
end
end
context 'when redis.sessions configuration is provided' do
it 'instantiates an instance of MultiStore' do
expect(described_class).to receive(:config_fallback?).and_return(false)
described_class.pool.with do |redis_instance|
expect(redis_instance).to be_instance_of(::Gitlab::Redis::MultiStore)
end
end
end
def clear_pool
described_class.remove_instance_variable(:@pool)
rescue NameError
# raised if @pool was not set; ignore
end
end
describe '#store' do
subject { described_class.store(namespace: described_class::SESSION_NAMESPACE) }
context 'when redis.sessions configuration is provided' do
it 'instantiates ::Redis instance' do
expect(described_class).to receive(:config_fallback?).and_return(true)
expect(subject).to be_instance_of(::Redis::Store)
end
end
context 'when redis.sessions configuration is not provided' do
it 'instantiates an instance of MultiStore' do
expect(described_class).to receive(:config_fallback?).and_return(false)
expect(subject).to be_instance_of(::Gitlab::Redis::MultiStore)
end
end
end
end
This diff is collapsed.
......@@ -376,24 +376,28 @@ RSpec.describe API::Commits do
end
end
context 'when using warden' do
it 'increments usage counters', :clean_gitlab_redis_shared_state do
session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d')
session_hash = { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] }
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
end
RSpec.shared_examples_for 'warden user session' do
context 'when using warden' do
it 'increments usage counters' do
session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d')
session_hash = { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] }
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
end
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
expect(::Gitlab::UsageDataCounters::WebIdeCounter).to receive(:increment_commits_count)
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_web_ide_edit_action)
expect(::Gitlab::UsageDataCounters::WebIdeCounter).to receive(:increment_commits_count)
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_web_ide_edit_action)
post api(url), params: valid_c_params
post api(url), params: valid_c_params
end
end
end
it_behaves_like 'redis sessions store', 'warden user session'
context 'a new file in project repo' do
before do
post api(url, user), params: valid_c_params
......
# frozen_string_literal: true
module SessionHelpers
def expect_single_session_with_authenticated_ttl
expect_single_session_with_expiration(Settings.gitlab['session_expire_delay'] * 60)
def expect_single_session_with_authenticated_ttl(redis_store_class)
expect_single_session_with_expiration(redis_store_class, Settings.gitlab['session_expire_delay'] * 60)
end
def expect_single_session_with_short_ttl
expect_single_session_with_expiration(Settings.gitlab['unauthenticated_session_expire_delay'])
def expect_single_session_with_short_ttl(redis_store_class)
expect_single_session_with_expiration(redis_store_class, Settings.gitlab['unauthenticated_session_expire_delay'])
end
def expect_single_session_with_expiration(expiration)
session_keys = get_session_keys
def expect_single_session_with_expiration(redis_store_class, expiration)
session_keys = get_session_keys(redis_store_class)
expect(session_keys.size).to eq(1)
expect(get_ttl(session_keys.first)).to be_within(5).of(expiration)
expect(get_ttl(redis_store_class, session_keys.first)).to be_within(5).of(expiration)
end
def get_session_keys
Gitlab::Redis::SharedState.with { |redis| redis.scan_each(match: 'session:gitlab:*').to_a }
def get_session_keys(redis_store_class)
redis_store_class.with { |redis| redis.scan_each(match: 'session:gitlab:*').to_a }
end
def get_ttl(key)
Gitlab::Redis::SharedState.with { |redis| redis.ttl(key) }
def get_ttl(redis_store_class, key)
redis_store_class.with { |redis| redis.ttl(key) }
end
end
......@@ -93,18 +93,23 @@ RSpec.shared_examples "redis_shared_examples" do
subject { described_class.new(rails_env).store }
shared_examples 'redis store' do
let(:redis_store) { ::Redis::Store }
let(:redis_store_to_s) { "Redis Client connected to #{host} against DB #{redis_database}" }
it 'instantiates Redis::Store' do
is_expected.to be_a(::Redis::Store)
expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database}")
is_expected.to be_a(redis_store)
expect(subject.to_s).to eq(redis_store_to_s)
end
context 'with the namespace' do
let(:namespace) { 'namespace_name' }
let(:redis_store_to_s) { "Redis Client connected to #{host} against DB #{redis_database} with namespace #{namespace}" }
subject { described_class.new(rails_env).store(namespace: namespace) }
it "uses specified namespace" do
expect(subject.to_s).to eq("Redis Client connected to #{host} against DB #{redis_database} with namespace #{namespace}")
expect(subject.to_s).to eq(redis_store_to_s)
end
end
end
......
# frozen_string_literal: true
RSpec.shared_examples 'redis sessions store' do |example|
context 'when ENV[GITLAB_USE_REDIS_SESSIONS_STORE] is true', :clean_gitlab_redis_sessions do
before do
stub_env('GITLAB_USE_REDIS_SESSIONS_STORE', 'true')
end
it_behaves_like example do
let(:redis_store_class) { Gitlab::Redis::Sessions }
end
end
context 'when ENV[GITLAB_USE_REDIS_SESSIONS_STORE] is false', :clean_gitlab_redis_shared_state do
before do
stub_env('GITLAB_USE_REDIS_SESSIONS_STORE', 'false')
end
it_behaves_like example do
let(:redis_store_class) { Gitlab::Redis::SharedState }
end
end
end
......@@ -18,32 +18,36 @@ RSpec.shared_examples 'snippet edit usage data counters' do
end
end
context 'when user is not sessionless' do
before do
session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d')
session_hash = { 'warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]] }
RSpec.shared_examples_for 'sessionless user' do
context 'when user is not sessionless' do
before do
session_id = Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d')
session_hash = { 'warden.user.user.key' => [[current_user.id], current_user.encrypted_password[0, 29]] }
Gitlab::Redis::SharedState.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
end
redis_store_class.with do |redis|
redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
end
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
end
cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
end
it 'tracks usage data actions', :clean_gitlab_redis_shared_state do
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_snippet_editor_edit_action)
it 'tracks usage data actions' do
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).to receive(:track_snippet_editor_edit_action)
post_graphql_mutation(mutation)
end
post_graphql_mutation(mutation)
end
context 'when mutation result raises an error' do
it 'does not track usage data actions' do
mutation_vars[:title] = nil
context 'when mutation result raises an error' do
it 'does not track usage data actions' do
mutation_vars[:title] = nil
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).not_to receive(:track_snippet_editor_edit_action)
expect(::Gitlab::UsageDataCounters::EditorUniqueCounter).not_to receive(:track_snippet_editor_edit_action)
post_graphql_mutation(mutation)
post_graphql_mutation(mutation)
end
end
end
end
it_behaves_like 'redis sessions store', 'sessionless user'
end
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment