Files
codeocean/spec/concerns/lti_spec.rb
Sebastian Serth 99bd46af1a Align project files with CodeHarbor
Since both projects are developed together and by the same team, we also want to have the same code structure and utility methods available in both projects. Therefore, this commit changes many files, but without a functional change.
2023-10-11 00:18:33 +02:00

186 lines
6.9 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
class Controller < AnonymousController
include Lti
end
RSpec.describe Lti do
let(:controller) { Controller.new }
let(:session) { double }
describe '#build_tool_provider' do
it 'instantiates a tool provider' do
expect(IMS::LTI::ToolProvider).to receive(:new)
controller.send(:build_tool_provider, consumer: build(:consumer), parameters: {})
end
end
describe '#external_user_name' do
let(:first_name) { 'Jane' }
let(:last_name) { 'Doe' }
let(:full_name) { 'John Doe' }
let(:provider) { double }
let(:provider_full) { instance_double(IMS::LTI::ToolProvider, lis_person_name_full: full_name) }
context 'when a full name is provided' do
it 'returns the full name' do
allow(provider_full).to receive(:lis_person_name_full).and_return(full_name)
expect(controller.send(:external_user_name, provider_full)).to eq(full_name)
end
end
context 'when only partial information is provided' do
it 'returns the first available name' do
expect(provider).to receive(:lis_person_name_full)
allow(provider).to receive(:lis_person_name_given).and_return(first_name)
expect(provider).not_to receive(:lis_person_name_family)
expect(controller.send(:external_user_name, provider)).to eq(first_name)
end
end
end
describe '#refuse_lti_launch' do
it 'returns to the tool consumer' do
message = I18n.t('sessions.oauth.invalid_consumer')
expect(controller).to receive(:return_to_consumer).with(lti_errorlog: message, lti_errormsg: I18n.t('sessions.oauth.failure'))
controller.send(:refuse_lti_launch, message:)
end
end
describe '#return_to_consumer' do
context 'with a return URL' do
let(:consumer_return_url) { 'https://example.org' }
let(:provider) { instance_double(IMS::LTI::ToolProvider, launch_presentation_return_url: consumer_return_url) }
before { controller.instance_variable_set(:@provider, provider) }
it 'redirects to the tool consumer' do
expect(controller).to receive(:redirect_to).with(consumer_return_url, allow_other_host: true)
controller.send(:return_to_consumer)
end
it 'passes messages to the consumer' do
message = I18n.t('sessions.oauth.failure')
expect(controller).to receive(:redirect_to).with("#{consumer_return_url}?lti_errorlog=#{CGI.escape(message)}", allow_other_host: true)
controller.send(:return_to_consumer, lti_errorlog: message)
end
end
context 'without a return URL' do
before do
allow(controller).to receive(:params).and_return({})
end
it 'redirects to the root URL' do
expect(controller).to receive(:redirect_to).with(:root)
controller.send(:return_to_consumer)
end
it 'displays alerts' do
message = I18n.t('sessions.oauth.failure')
controller.send(:return_to_consumer, lti_errormsg: message)
expect(controller.instance_variable_get(:@flash)[:danger]).to eq(obtain_message(message))
end
it 'displays notices' do
message = I18n.t('sessions.destroy_through_lti.success_without_outcome')
controller.send(:return_to_consumer, lti_msg: message)
expect(controller.instance_variable_get(:@flash)[:info]).to eq(obtain_message(message))
end
end
end
describe '#send_scores' do
let(:consumer) { create(:consumer) }
let(:score) { 0.5 }
let(:submission) { create(:submission) }
before do
create(:lti_parameter, external_user: submission.contributor, exercise: submission.exercise)
end
context 'with an invalid score' do
it 'raises an exception' do
allow(submission).to receive(:normalized_score).and_return Lti::MAXIMUM_SCORE * 2
expect { controller.send(:send_scores, submission) }.to raise_error(Lti::Error)
end
end
context 'with an valid score' do
context 'with a tool consumer' do
context 'when grading is not supported' do
it 'returns a corresponding status' do
allow_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(false)
allow(submission).to receive(:normalized_score).and_return score
expect(controller.send(:send_scores, submission).first[:status]).to eq('unsupported')
end
end
context 'when grading is supported' do
let(:response) { double }
let(:send_scores) { controller.send(:send_scores, submission).first }
before do
allow_any_instance_of(IMS::LTI::ToolProvider).to receive(:outcome_service?).and_return(true)
allow_any_instance_of(IMS::LTI::ToolProvider).to receive(:post_replace_result!).with(score).and_return(response)
allow(response).to receive(:response_code).at_least(:once).and_return(200)
allow(response).to receive(:post_response).and_return(response)
allow(response).to receive(:body).at_least(:once).and_return('')
allow(response).to receive(:code_major).at_least(:once).and_return('success')
allow(submission).to receive(:normalized_score).and_return score
end
it 'sends the score' do
expect_any_instance_of(IMS::LTI::ToolProvider).to receive(:post_replace_result!).with(score)
send_scores
end
it 'returns code, message, and status' do
expect(send_scores[:code]).to eq(response.response_code)
expect(send_scores[:message]).to eq(response.body)
expect(send_scores[:status]).to eq(response.code_major)
end
end
end
context 'without a tool consumer' do
it 'returns a corresponding status' do
submission.contributor.consumer = nil
allow(submission).to receive(:normalized_score).and_return score
expect(controller.send(:send_scores, submission).first[:status]).to eq('error')
end
end
end
end
describe '#store_lti_session_data' do
let(:parameters) { ActionController::Parameters.new({}) }
it 'stores data in the session' do
controller.instance_variable_set(:@current_user, create(:external_user))
controller.instance_variable_set(:@exercise, create(:fibonacci))
expect(controller.session).to receive(:[]=).with(:external_user_id, anything)
controller.send(:store_lti_session_data, parameters)
end
it 'creates an LtiParameter Object' do
expect do
controller.instance_variable_set(:@current_user, create(:external_user))
controller.instance_variable_set(:@exercise, create(:fibonacci))
controller.send(:store_lti_session_data, parameters)
end.to change(LtiParameter, :count).by(1)
end
end
describe '#store_nonce' do
it 'adds a nonce to the nonce store' do
nonce = SecureRandom.hex
expect(NonceStore).to receive(:add).with(nonce)
controller.send(:store_nonce, nonce)
end
end
end