dawarich/spec/services/tracks/session_manager_spec.rb
2025-07-28 22:30:36 +02:00

339 lines
No EOL
9.2 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Tracks::SessionManager do
let(:user_id) { 123 }
let(:session_id) { 'test-session-id' }
let(:manager) { described_class.new(user_id, session_id) }
before do
Rails.cache.clear
end
describe '#initialize' do
it 'creates manager with provided user_id and session_id' do
expect(manager.user_id).to eq(user_id)
expect(manager.session_id).to eq(session_id)
end
it 'generates UUID session_id when not provided' do
manager = described_class.new(user_id)
expect(manager.session_id).to match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
end
end
describe '#create_session' do
let(:metadata) { { mode: 'bulk', chunk_size: '1.day' } }
it 'creates a new session with default values' do
result = manager.create_session(metadata)
expect(result).to eq(manager)
expect(manager.session_exists?).to be true
session_data = manager.get_session_data
expect(session_data['status']).to eq('pending')
expect(session_data['total_chunks']).to eq(0)
expect(session_data['completed_chunks']).to eq(0)
expect(session_data['tracks_created']).to eq(0)
expect(session_data['metadata']).to eq(metadata.deep_stringify_keys)
expect(session_data['started_at']).to be_present
expect(session_data['completed_at']).to be_nil
expect(session_data['error_message']).to be_nil
end
it 'sets TTL on the cache entry' do
manager.create_session(metadata)
# Check that the key exists and will expire
expect(Rails.cache.exist?(manager.send(:cache_key))).to be true
end
end
describe '#get_session_data' do
it 'returns nil when session does not exist' do
expect(manager.get_session_data).to be_nil
end
it 'returns session data when session exists' do
metadata = { test: 'data' }
manager.create_session(metadata)
data = manager.get_session_data
expect(data).to be_a(Hash)
expect(data['metadata']).to eq(metadata.deep_stringify_keys)
end
end
describe '#session_exists?' do
it 'returns false when session does not exist' do
expect(manager.session_exists?).to be false
end
it 'returns true when session exists' do
manager.create_session
expect(manager.session_exists?).to be true
end
end
describe '#update_session' do
before do
manager.create_session
end
it 'updates existing session data' do
updates = { status: 'processing', total_chunks: 5 }
result = manager.update_session(updates)
expect(result).to be true
data = manager.get_session_data
expect(data['status']).to eq('processing')
expect(data['total_chunks']).to eq(5)
end
it 'returns false when session does not exist' do
manager.cleanup_session
result = manager.update_session({ status: 'processing' })
expect(result).to be false
end
it 'preserves existing data when updating' do
original_metadata = { mode: 'bulk' }
manager.cleanup_session
manager.create_session(original_metadata)
manager.update_session({ status: 'processing' })
data = manager.get_session_data
expect(data['metadata']).to eq(original_metadata.stringify_keys)
expect(data['status']).to eq('processing')
end
end
describe '#mark_started' do
before do
manager.create_session
end
it 'marks session as processing with total chunks' do
result = manager.mark_started(10)
expect(result).to be true
data = manager.get_session_data
expect(data['status']).to eq('processing')
expect(data['total_chunks']).to eq(10)
expect(data['started_at']).to be_present
end
end
describe '#increment_completed_chunks' do
before do
manager.create_session
manager.mark_started(5)
end
it 'increments completed chunks counter' do
expect {
manager.increment_completed_chunks
}.to change {
manager.get_session_data['completed_chunks']
}.from(0).to(1)
end
it 'returns false when session does not exist' do
manager.cleanup_session
expect(manager.increment_completed_chunks).to be false
end
end
describe '#increment_tracks_created' do
before do
manager.create_session
end
it 'increments tracks created counter by 1 by default' do
expect {
manager.increment_tracks_created
}.to change {
manager.get_session_data['tracks_created']
}.from(0).to(1)
end
it 'increments tracks created counter by specified amount' do
expect {
manager.increment_tracks_created(5)
}.to change {
manager.get_session_data['tracks_created']
}.from(0).to(5)
end
it 'returns false when session does not exist' do
manager.cleanup_session
expect(manager.increment_tracks_created).to be false
end
end
describe '#mark_completed' do
before do
manager.create_session
end
it 'marks session as completed with timestamp' do
result = manager.mark_completed
expect(result).to be true
data = manager.get_session_data
expect(data['status']).to eq('completed')
expect(data['completed_at']).to be_present
end
end
describe '#mark_failed' do
before do
manager.create_session
end
it 'marks session as failed with error message and timestamp' do
error_message = 'Something went wrong'
result = manager.mark_failed(error_message)
expect(result).to be true
data = manager.get_session_data
expect(data['status']).to eq('failed')
expect(data['error_message']).to eq(error_message)
expect(data['completed_at']).to be_present
end
end
describe '#all_chunks_completed?' do
before do
manager.create_session
manager.mark_started(3)
end
it 'returns false when not all chunks are completed' do
manager.increment_completed_chunks
expect(manager.all_chunks_completed?).to be false
end
it 'returns true when all chunks are completed' do
3.times { manager.increment_completed_chunks }
expect(manager.all_chunks_completed?).to be true
end
it 'returns true when completed chunks exceed total (edge case)' do
4.times { manager.increment_completed_chunks }
expect(manager.all_chunks_completed?).to be true
end
it 'returns false when session does not exist' do
manager.cleanup_session
expect(manager.all_chunks_completed?).to be false
end
end
describe '#progress_percentage' do
before do
manager.create_session
end
it 'returns 0 when session does not exist' do
manager.cleanup_session
expect(manager.progress_percentage).to eq(0)
end
it 'returns 100 when total chunks is 0' do
expect(manager.progress_percentage).to eq(100)
end
it 'calculates correct percentage' do
manager.mark_started(4)
2.times { manager.increment_completed_chunks }
expect(manager.progress_percentage).to eq(50.0)
end
it 'rounds to 2 decimal places' do
manager.mark_started(3)
manager.increment_completed_chunks
expect(manager.progress_percentage).to eq(33.33)
end
end
describe '#cleanup_session' do
before do
manager.create_session
end
it 'removes session from cache' do
expect(manager.session_exists?).to be true
manager.cleanup_session
expect(manager.session_exists?).to be false
end
end
describe '.create_for_user' do
let(:metadata) { { mode: 'daily' } }
it 'creates and returns a session manager' do
result = described_class.create_for_user(user_id, metadata)
expect(result).to be_a(described_class)
expect(result.user_id).to eq(user_id)
expect(result.session_exists?).to be true
data = result.get_session_data
expect(data['metadata']).to eq(metadata.deep_stringify_keys)
end
end
describe '.find_session' do
it 'returns nil when session does not exist' do
result = described_class.find_session(user_id, 'non-existent')
expect(result).to be_nil
end
it 'returns session manager when session exists' do
manager.create_session
result = described_class.find_session(user_id, session_id)
expect(result).to be_a(described_class)
expect(result.user_id).to eq(user_id)
expect(result.session_id).to eq(session_id)
end
end
describe '.cleanup_expired_sessions' do
it 'returns true (no-op with Rails.cache TTL)' do
expect(described_class.cleanup_expired_sessions).to be true
end
end
describe 'cache key scoping' do
it 'uses user-scoped cache keys' do
expected_key = "track_generation:user:#{user_id}:session:#{session_id}"
actual_key = manager.send(:cache_key)
expect(actual_key).to eq(expected_key)
end
it 'prevents cross-user session access' do
manager.create_session
other_manager = described_class.new(999, session_id)
expect(manager.session_exists?).to be true
expect(other_manager.session_exists?).to be false
end
end
end