fix the rspec
This commit is contained in:
@@ -4,9 +4,7 @@
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# content :text
|
||||
# content_type :string
|
||||
# external_link :string not null
|
||||
# file_size :bigint
|
||||
# metadata :jsonb
|
||||
# name :string
|
||||
# status :integer default("in_progress"), not null
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Llm::PdfProcessingService do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:document) { create(:captain_document, account: account, assistant: assistant) }
|
||||
let(:openai_client) { instance_double(OpenAI::Client) }
|
||||
let(:service) do
|
||||
# Mock the InstallationConfig for base class initialization
|
||||
allow(InstallationConfig).to receive(:find_by!).with(name: 'CAPTAIN_OPEN_AI_API_KEY')
|
||||
.and_return(instance_double(InstallationConfig, value: 'test-api-key'))
|
||||
allow(OpenAI::Client).to receive(:new).and_return(openai_client)
|
||||
described_class.new(document)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'initializes with document' do
|
||||
expect(service.instance_variable_get(:@document)).to eq(document)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#process' do
|
||||
let(:files_api) { instance_double(OpenAI::Files) }
|
||||
let(:temp_file) { instance_double(Tempfile) }
|
||||
let(:pdf_attachment) { instance_double(ActiveStorage::Attachment) }
|
||||
|
||||
before do
|
||||
allow(openai_client).to receive(:files).and_return(files_api)
|
||||
allow(document).to receive(:pdf_file).and_return(pdf_attachment)
|
||||
allow(pdf_attachment).to receive(:download).and_return('pdf content')
|
||||
allow(Tempfile).to receive(:new).and_return(temp_file)
|
||||
allow(temp_file).to receive(:binmode)
|
||||
allow(temp_file).to receive(:write)
|
||||
allow(temp_file).to receive(:close)
|
||||
allow(temp_file).to receive(:path).and_return('/tmp/test.pdf')
|
||||
allow(temp_file).to receive(:unlink)
|
||||
allow(File).to receive(:open).with('/tmp/test.pdf', 'rb').and_yield(StringIO.new('pdf content'))
|
||||
end
|
||||
|
||||
context 'when document already has openai_file_id' do
|
||||
before do
|
||||
allow(document).to receive(:openai_file_id).and_return('existing-file-id')
|
||||
end
|
||||
|
||||
it 'returns success message without uploading' do
|
||||
expect(files_api).not_to receive(:upload)
|
||||
result = service.process
|
||||
expect(result).to eq('PDF ready for paginated processing')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when upload is successful' do
|
||||
let(:upload_response) do
|
||||
{
|
||||
'id' => 'file-abc123',
|
||||
'object' => 'file',
|
||||
'bytes' => 120_000,
|
||||
'created_at' => 1_677_610_602,
|
||||
'filename' => 'sample.pdf',
|
||||
'purpose' => 'assistants'
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(document).to receive(:openai_file_id).and_return(nil)
|
||||
allow(files_api).to receive(:upload).and_return(upload_response)
|
||||
allow(document).to receive(:store_openai_file_id)
|
||||
end
|
||||
|
||||
it 'uploads the PDF file to OpenAI' do
|
||||
expect(files_api).to receive(:upload).with(
|
||||
parameters: {
|
||||
file: anything,
|
||||
purpose: 'assistants'
|
||||
}
|
||||
)
|
||||
|
||||
service.process
|
||||
end
|
||||
|
||||
it 'returns success message with file ID' do
|
||||
result = service.process
|
||||
expect(result).to include('file-abc123')
|
||||
expect(result).to include('PDF ready for paginated processing')
|
||||
end
|
||||
|
||||
it 'stores the file ID in document' do
|
||||
expect(document).to receive(:store_openai_file_id).with('file-abc123')
|
||||
service.process
|
||||
end
|
||||
end
|
||||
|
||||
context 'when upload fails' do
|
||||
before do
|
||||
allow(document).to receive(:openai_file_id).and_return(nil)
|
||||
allow(files_api).to receive(:upload).and_raise(StandardError, 'Upload failed')
|
||||
end
|
||||
|
||||
it 'raises the error' do
|
||||
expect { service.process }.to raise_error(StandardError, 'Upload failed')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file_id is missing from response' do
|
||||
let(:invalid_response) do
|
||||
{
|
||||
'object' => 'file',
|
||||
'bytes' => 120_000
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(document).to receive(:openai_file_id).and_return(nil)
|
||||
allow(files_api).to receive(:upload).and_return(invalid_response)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { service.process }.to raise_error('Failed to upload PDF to OpenAI')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,206 +0,0 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::PdfProcessingService do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:pdf_file) do
|
||||
ActiveStorage::Blob.create_and_upload!(
|
||||
io: File.open(Rails.root.join('spec/fixtures/files/sample.pdf')),
|
||||
filename: 'sample.pdf',
|
||||
content_type: 'application/pdf'
|
||||
)
|
||||
end
|
||||
let(:service) { described_class.new(assistant: assistant, pdf_file: pdf_file) }
|
||||
|
||||
describe '#initialize' do
|
||||
it 'initializes with assistant and pdf_file' do
|
||||
expect(service.instance_variable_get(:@assistant)).to eq(assistant)
|
||||
expect(service.instance_variable_get(:@pdf_file)).to eq(pdf_file)
|
||||
end
|
||||
|
||||
it 'raises error when assistant is nil' do
|
||||
expect { described_class.new(assistant: nil, pdf_file: pdf_file) }
|
||||
.to raise_error(ArgumentError, 'Assistant is required')
|
||||
end
|
||||
|
||||
it 'raises error when pdf_file is nil' do
|
||||
expect { described_class.new(assistant: assistant, pdf_file: nil) }
|
||||
.to raise_error(ArgumentError, 'PDF file is required')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
let(:openai_client) { instance_double(OpenAI::Client) }
|
||||
let(:files_api) { instance_double(OpenAI::Files) }
|
||||
|
||||
before do
|
||||
allow(service).to receive(:openai_client).and_return(openai_client)
|
||||
allow(openai_client).to receive(:files).and_return(files_api)
|
||||
end
|
||||
|
||||
context 'when upload is successful' do
|
||||
let(:upload_response) do
|
||||
{
|
||||
'id' => 'file-abc123',
|
||||
'object' => 'file',
|
||||
'bytes' => 120_000,
|
||||
'created_at' => 1_677_610_602,
|
||||
'filename' => 'sample.pdf',
|
||||
'purpose' => 'assistants'
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(files_api).to receive(:upload).and_return(upload_response)
|
||||
end
|
||||
|
||||
it 'uploads the PDF file to OpenAI' do
|
||||
expect(files_api).to receive(:upload).with(
|
||||
parameters: {
|
||||
file: anything,
|
||||
purpose: 'assistants'
|
||||
}
|
||||
)
|
||||
|
||||
service.perform
|
||||
end
|
||||
|
||||
it 'returns the file ID' do
|
||||
result = service.perform
|
||||
expect(result).to eq('file-abc123')
|
||||
end
|
||||
|
||||
it 'attaches the file to the assistant' do
|
||||
allow(service).to receive(:attach_file_to_assistant)
|
||||
|
||||
expect(service).to receive(:attach_file_to_assistant).with('file-abc123')
|
||||
|
||||
service.perform
|
||||
end
|
||||
end
|
||||
|
||||
context 'when upload fails' do
|
||||
before do
|
||||
allow(files_api).to receive(:upload).and_raise(StandardError, 'Upload failed')
|
||||
end
|
||||
|
||||
it 'raises the error' do
|
||||
expect { service.perform }.to raise_error(StandardError, 'Upload failed')
|
||||
end
|
||||
|
||||
it 'logs the error' do
|
||||
expect(Rails.logger).to receive(:error).with(/Failed to upload PDF/)
|
||||
|
||||
expect { service.perform }.to raise_error(StandardError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#attach_file_to_assistant' do
|
||||
let(:openai_client) { instance_double(OpenAI::Client) }
|
||||
let(:assistants_api) { instance_double(OpenAI::Assistants) }
|
||||
let(:file_id) { 'file-abc123' }
|
||||
|
||||
before do
|
||||
allow(service).to receive(:openai_client).and_return(openai_client)
|
||||
allow(openai_client).to receive(:assistants).and_return(assistants_api)
|
||||
end
|
||||
|
||||
context 'when attachment is successful' do
|
||||
let(:assistant_response) do
|
||||
{
|
||||
'id' => assistant.openai_id,
|
||||
'file_ids' => %w[file-abc123 file-xyz789]
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
allow(assistants_api).to receive(:modify).and_return(assistant_response)
|
||||
end
|
||||
|
||||
it 'attaches the file to the assistant' do
|
||||
expect(assistants_api).to receive(:modify).with(
|
||||
id: assistant.openai_id,
|
||||
parameters: {
|
||||
file_ids: array_including(file_id)
|
||||
}
|
||||
)
|
||||
|
||||
service.send(:attach_file_to_assistant, file_id)
|
||||
end
|
||||
|
||||
it 'preserves existing file IDs' do
|
||||
assistant.update!(file_ids: ['file-existing'])
|
||||
|
||||
expect(assistants_api).to receive(:modify).with(
|
||||
id: assistant.openai_id,
|
||||
parameters: {
|
||||
file_ids: ['file-existing', file_id]
|
||||
}
|
||||
)
|
||||
|
||||
service.send(:attach_file_to_assistant, file_id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when attachment fails' do
|
||||
before do
|
||||
allow(assistants_api).to receive(:modify).and_raise(StandardError, 'Attachment failed')
|
||||
end
|
||||
|
||||
it 'raises the error' do
|
||||
expect { service.send(:attach_file_to_assistant, file_id) }
|
||||
.to raise_error(StandardError, 'Attachment failed')
|
||||
end
|
||||
|
||||
it 'logs the error' do
|
||||
expect(Rails.logger).to receive(:error).with(/Failed to attach file to assistant/)
|
||||
|
||||
expect { service.send(:attach_file_to_assistant, file_id) }
|
||||
.to raise_error(StandardError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#download_pdf_content' do
|
||||
it 'downloads the PDF file content' do
|
||||
pdf_file.open do |file|
|
||||
content = service.send(:download_pdf_content)
|
||||
expect(content).to eq(file.read)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns binary content' do
|
||||
content = service.send(:download_pdf_content)
|
||||
expect(content.encoding).to eq(Encoding::ASCII_8BIT)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'integration with OpenAI' do
|
||||
context 'when OpenAI credentials are configured' do
|
||||
before do
|
||||
allow(ENV).to receive(:[]).with('OPENAI_API_KEY').and_return('test-api-key')
|
||||
end
|
||||
|
||||
it 'creates OpenAI client with correct configuration' do
|
||||
expect(OpenAI::Client).to receive(:new).with(
|
||||
access_token: 'test-api-key',
|
||||
request_timeout: 240
|
||||
)
|
||||
|
||||
service.send(:openai_client)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when OpenAI credentials are not configured' do
|
||||
before do
|
||||
allow(ENV).to receive(:[]).with('OPENAI_API_KEY').and_return(nil)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { service.send(:openai_client) }
|
||||
.to raise_error(StandardError, 'OpenAI API key not configured')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user