specs for services
This commit is contained in:
76
spec/services/exercise_service/check_external_spec.rb
Normal file
76
spec/services/exercise_service/check_external_spec.rb
Normal file
@ -0,0 +1,76 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ExerciseService::CheckExternal do
|
||||
describe '.new' do
|
||||
subject(:export_service) { described_class.new(uuid: uuid, codeharbor_link: codeharbor_link) }
|
||||
|
||||
let(:uuid) { SecureRandom.uuid }
|
||||
let(:codeharbor_link) { FactoryBot.build(:codeharbor_link) }
|
||||
|
||||
it 'assigns uuid' do
|
||||
expect(export_service.instance_variable_get(:@uuid)).to be uuid
|
||||
end
|
||||
|
||||
it 'assigns codeharbor_link' do
|
||||
expect(export_service.instance_variable_get(:@codeharbor_link)).to be codeharbor_link
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:check_external_service) { described_class.call(uuid: uuid, codeharbor_link: codeharbor_link) }
|
||||
|
||||
let(:uuid) { SecureRandom.uuid }
|
||||
let(:codeharbor_link) { FactoryBot.build(:codeharbor_link) }
|
||||
let(:response) { {}.to_json }
|
||||
|
||||
before { stub_request(:post, codeharbor_link.check_uuid_url).to_return(body: response) }
|
||||
|
||||
it 'calls the correct url' do
|
||||
expect(check_external_service).to have_requested(:post, codeharbor_link.check_uuid_url)
|
||||
end
|
||||
|
||||
it 'submits the correct headers' do
|
||||
expect(check_external_service).to have_requested(:post, codeharbor_link.check_uuid_url)
|
||||
.with(headers: {content_type: 'application/json', authorization: "Bearer #{codeharbor_link.api_key}"})
|
||||
end
|
||||
|
||||
it 'submits the correct body' do
|
||||
expect(check_external_service).to have_requested(:post, codeharbor_link.check_uuid_url)
|
||||
.with(body: {uuid: uuid}.to_json)
|
||||
end
|
||||
|
||||
context 'when response contains a JSON with expected keys' do
|
||||
let(:response) { {message: 'message', exercise_found: true, update_right: true}.to_json }
|
||||
|
||||
it 'returns the correct hash' do
|
||||
expect(check_external_service).to eql(error: false, message: 'message', exercise_found: true, update_right: true)
|
||||
end
|
||||
|
||||
context 'with different values' do
|
||||
let(:response) { {message: 'message', exercise_found: false, update_right: false}.to_json }
|
||||
|
||||
it 'returns the correct hash' do
|
||||
expect(check_external_service).to eql(error: false, message: 'message', exercise_found: false, update_right: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when response does not contain JSON' do
|
||||
let(:response) { 'foo' }
|
||||
|
||||
it 'returns the correct hash' do
|
||||
expect(check_external_service).to eql(error: true, message: I18n.t('exercises.export_codeharbor.error'))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the request fails' do
|
||||
before { allow(Faraday).to receive(:new).and_raise(Faraday::Error, 'error') }
|
||||
|
||||
it 'returns the correct hash' do
|
||||
expect(check_external_service).to eql(error: true, message: I18n.t('exercises.export_codeharbor.error'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
64
spec/services/exercise_service/push_external_spec.rb
Normal file
64
spec/services/exercise_service/push_external_spec.rb
Normal file
@ -0,0 +1,64 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ExerciseService::PushExternal do
|
||||
describe '.new' do
|
||||
subject(:push_external) { described_class.new(zip: zip, codeharbor_link: codeharbor_link) }
|
||||
|
||||
let(:zip) { ProformaService::ExportTask.call(exercise: FactoryBot.build(:dummy)) }
|
||||
let(:codeharbor_link) { FactoryBot.build(:codeharbor_link) }
|
||||
|
||||
it 'assigns zip' do
|
||||
expect(push_external.instance_variable_get(:@zip)).to be zip
|
||||
end
|
||||
|
||||
it 'assigns codeharbor_link' do
|
||||
expect(push_external.instance_variable_get(:@codeharbor_link)).to be codeharbor_link
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:push_external) { described_class.call(zip: zip, codeharbor_link: codeharbor_link) }
|
||||
|
||||
let(:zip) { ProformaService::ExportTask.call(exercise: FactoryBot.build(:dummy)) }
|
||||
let(:codeharbor_link) { FactoryBot.build(:codeharbor_link) }
|
||||
let(:status) { 200 }
|
||||
let(:response) { '' }
|
||||
|
||||
before { stub_request(:post, codeharbor_link.push_url).to_return(status: status, body: response) }
|
||||
|
||||
it 'calls the correct url' do
|
||||
expect(push_external).to have_requested(:post, codeharbor_link.push_url)
|
||||
end
|
||||
|
||||
it 'submits the correct headers' do
|
||||
expect(push_external).to have_requested(:post, codeharbor_link.push_url)
|
||||
.with(headers: {content_type: 'application/zip',
|
||||
authorization: "Bearer #{codeharbor_link.api_key}",
|
||||
content_length: zip.string.length})
|
||||
end
|
||||
|
||||
it 'submits the correct body' do
|
||||
expect(push_external).to have_requested(:post, codeharbor_link.push_url)
|
||||
.with(body: zip.string)
|
||||
end
|
||||
|
||||
context 'when response status is success' do
|
||||
it { is_expected.to be nil }
|
||||
|
||||
context 'when response status is 500' do
|
||||
let(:status) { 500 }
|
||||
let(:response) { 'an error occured' }
|
||||
|
||||
it { is_expected.to be response }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an error occurs' do
|
||||
before { allow(Faraday).to receive(:new).and_raise(StandardError) }
|
||||
|
||||
it { is_expected.not_to be nil }
|
||||
end
|
||||
end
|
||||
end
|
198
spec/services/proforma_service/convert_exercise_to_task_spec.rb
Normal file
198
spec/services/proforma_service/convert_exercise_to_task_spec.rb
Normal file
@ -0,0 +1,198 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ProformaService::ConvertExerciseToTask do
|
||||
describe '.new' do
|
||||
subject(:convert_to_task) { described_class.new(exercise: exercise) }
|
||||
|
||||
let(:exercise) { FactoryBot.build(:dummy) }
|
||||
|
||||
it 'assigns exercise' do
|
||||
expect(convert_to_task.instance_variable_get(:@exercise)).to be exercise
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:task) { convert_to_task.execute }
|
||||
|
||||
let(:convert_to_task) { described_class.new(exercise: exercise) }
|
||||
let(:exercise) do
|
||||
FactoryBot.create(:dummy,
|
||||
instructions: 'instruction',
|
||||
uuid: SecureRandom.uuid,
|
||||
files: files + tests)
|
||||
end
|
||||
let(:files) { [] }
|
||||
let(:tests) { [] }
|
||||
|
||||
it 'creates a task with all basic attributes' do
|
||||
expect(task).to have_attributes(
|
||||
title: exercise.title,
|
||||
description: exercise.description,
|
||||
internal_description: exercise.instructions,
|
||||
# proglang: {
|
||||
# name: exercise.execution_environment.language,
|
||||
# version: exercise.execution_environment.version
|
||||
# },
|
||||
uuid: exercise.uuid,
|
||||
language: described_class::DEFAULT_LANGUAGE,
|
||||
# parent_uuid: exercise.clone_relations.first&.origin&.uuid,
|
||||
files: [],
|
||||
tests: [],
|
||||
model_solutions: [],
|
||||
import_checksum: exercise.import_checksum
|
||||
)
|
||||
end
|
||||
|
||||
context 'when exercise has a mainfile' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file) }
|
||||
|
||||
it 'creates a task-file with the correct attributes' do
|
||||
expect(task.files.first).to have_attributes(
|
||||
id: file.id,
|
||||
content: file.content,
|
||||
filename: file.name_with_extension,
|
||||
used_by_grader: true,
|
||||
usage_by_lms: 'edit',
|
||||
visible: 'yes',
|
||||
binary: false,
|
||||
internal_description: 'main_file'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a regular file' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file, role: 'regular_file', hidden: hidden, read_only: read_only) }
|
||||
let(:hidden) { true }
|
||||
let(:read_only) { true }
|
||||
|
||||
it 'creates a task-file with the correct attributes' do
|
||||
expect(task.files.first).to have_attributes(
|
||||
id: file.id,
|
||||
content: file.content,
|
||||
filename: file.name_with_extension,
|
||||
used_by_grader: true,
|
||||
usage_by_lms: 'display',
|
||||
visible: 'no',
|
||||
binary: false,
|
||||
internal_description: 'regular_file'
|
||||
)
|
||||
end
|
||||
|
||||
context 'when file is not hidden' do
|
||||
let(:hidden) { false }
|
||||
|
||||
it 'creates a task-file with the correct attributes' do
|
||||
expect(task.files.first).to have_attributes(visible: 'yes')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file is not read_only' do
|
||||
let(:read_only) { false }
|
||||
|
||||
it 'creates a task-file with the correct attributes' do
|
||||
expect(task.files.first).to have_attributes(usage_by_lms: 'edit')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file has an attachment' do
|
||||
let(:file) { FactoryBot.build(:file, :image, role: 'regular_file') }
|
||||
|
||||
it 'creates a task-file with the correct attributes' do
|
||||
expect(task.files.first).to have_attributes(
|
||||
used_by_grader: false,
|
||||
binary: true,
|
||||
mimetype: 'image/png'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a file with role reference implementation' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file, role: 'reference_implementation') }
|
||||
|
||||
it 'creates a task with one model-solution' do
|
||||
expect(task.model_solutions).to have(1).item
|
||||
end
|
||||
|
||||
it 'creates a model-solution with one file' do
|
||||
expect(task.model_solutions.first).to have_attributes(
|
||||
id: "ms-#{file.id}",
|
||||
files: have(1).item
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates a model-solution with one file with correct attributes' do
|
||||
expect(task.model_solutions.first.files.first).to have_attributes(
|
||||
id: file.id,
|
||||
content: file.content,
|
||||
filename: file.name_with_extension,
|
||||
used_by_grader: false,
|
||||
usage_by_lms: 'display',
|
||||
visible: 'delayed',
|
||||
binary: false,
|
||||
internal_description: 'reference_implementation'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has multiple files with role reference implementation' do
|
||||
let(:files) { FactoryBot.build_list(:file, 2, role: 'reference_implementation') }
|
||||
|
||||
it 'creates a task with two model-solutions' do
|
||||
expect(task.model_solutions).to have(2).items
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a test' do
|
||||
let(:tests) { [test_file] }
|
||||
let(:test_file) { FactoryBot.build(:test_file) }
|
||||
# let(:file) { FactoryBot.build(:codeharbor_test_file) }
|
||||
|
||||
it 'creates a task with one test' do
|
||||
expect(task.tests).to have(1).item
|
||||
end
|
||||
|
||||
it 'creates a test with one file' do
|
||||
expect(task.tests.first).to have_attributes(
|
||||
id: test_file.id,
|
||||
title: test_file.name,
|
||||
files: have(1).item,
|
||||
meta_data: {'feedback-message' => test_file.feedback_message}
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates a test with one file with correct attributes' do
|
||||
expect(task.tests.first.files.first).to have_attributes(
|
||||
id: test_file.id,
|
||||
content: test_file.content,
|
||||
filename: test_file.name_with_extension,
|
||||
used_by_grader: true,
|
||||
visible: 'no',
|
||||
binary: false,
|
||||
internal_description: 'teacher_defined_test'
|
||||
)
|
||||
end
|
||||
|
||||
context 'when exercise_file is not hidden' do
|
||||
let(:test_file) { FactoryBot.create(:test_file, hidden: false) }
|
||||
|
||||
it 'creates the test file with the correct attribute' do
|
||||
expect(task.tests.first.files.first).to have_attributes(visible: 'yes')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has multiple tests' do
|
||||
let(:tests) { FactoryBot.build_list(:test_file, 2) }
|
||||
|
||||
it 'creates a task with two tests' do
|
||||
expect(task.tests).to have(2).items
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
377
spec/services/proforma_service/convert_task_to_exercise_spec.rb
Normal file
377
spec/services/proforma_service/convert_task_to_exercise_spec.rb
Normal file
@ -0,0 +1,377 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ProformaService::ConvertTaskToExercise do
|
||||
describe '.new' do
|
||||
subject(:convert_to_exercise_service) { described_class.new(task: task, user: user, exercise: exercise) }
|
||||
|
||||
let(:task) { Proforma::Task.new }
|
||||
let(:user) { FactoryBot.build(:teacher) }
|
||||
let(:exercise) { FactoryBot.build(:dummy) }
|
||||
|
||||
it 'assigns task' do
|
||||
expect(convert_to_exercise_service.instance_variable_get(:@task)).to be task
|
||||
end
|
||||
|
||||
it 'assigns user' do
|
||||
expect(convert_to_exercise_service.instance_variable_get(:@user)).to be user
|
||||
end
|
||||
|
||||
it 'assigns exercise' do
|
||||
expect(convert_to_exercise_service.instance_variable_get(:@exercise)).to be exercise
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:convert_to_exercise_service) { described_class.call(task: task, user: user, exercise: exercise) }
|
||||
|
||||
before { FactoryBot.create(:dot_txt) }
|
||||
|
||||
let(:task) do
|
||||
Proforma::Task.new(
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
internal_description: 'internal_description',
|
||||
proglang: {name: 'proglang-name', version: 'proglang-version'},
|
||||
uuid: 'uuid',
|
||||
parent_uuid: 'parent_uuid',
|
||||
language: 'language',
|
||||
model_solutions: model_solutions,
|
||||
files: files,
|
||||
tests: tests,
|
||||
import_checksum: 'import_checksum',
|
||||
checksum: 'checksum'
|
||||
)
|
||||
end
|
||||
let(:user) { FactoryBot.create(:teacher) }
|
||||
let(:files) { [] }
|
||||
let(:tests) { [] }
|
||||
let(:model_solutions) { [] }
|
||||
let(:exercise) {}
|
||||
|
||||
it 'creates an exercise with the correct attributes' do
|
||||
expect(convert_to_exercise_service).to have_attributes(
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
instructions: 'internal_description',
|
||||
execution_environment: be_blank,
|
||||
uuid: be_blank,
|
||||
unpublished: true,
|
||||
user: user,
|
||||
files: be_empty
|
||||
)
|
||||
end
|
||||
|
||||
context 'when task has a file' do
|
||||
let(:files) { [file] }
|
||||
let(:file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'id',
|
||||
content: content,
|
||||
filename: 'filename.txt',
|
||||
used_by_grader: 'used_by_grader',
|
||||
visible: 'yes',
|
||||
usage_by_lms: usage_by_lms,
|
||||
binary: binary,
|
||||
internal_description: 'regular_file',
|
||||
mimetype: mimetype
|
||||
)
|
||||
end
|
||||
let(:usage_by_lms) { 'display' }
|
||||
let(:mimetype) { 'mimetype' }
|
||||
let(:binary) { false }
|
||||
let(:content) { 'content' }
|
||||
|
||||
it 'creates an exercise with a file that has the correct attributes' do
|
||||
expect(convert_to_exercise_service.files.first).to have_attributes(
|
||||
content: 'content',
|
||||
name: 'filename',
|
||||
role: 'regular_file',
|
||||
hidden: false,
|
||||
read_only: true,
|
||||
file_type: be_a(FileType).and(have_attributes(file_extension: '.txt'))
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates a new Exercise on save' do
|
||||
expect { convert_to_exercise_service.save! }.to change(Exercise, :count).by(1)
|
||||
end
|
||||
|
||||
context 'when file is very large' do
|
||||
let(:content) { 'test' * 10**5 }
|
||||
|
||||
it 'creates an exercise with a file that has the correct attributes' do
|
||||
expect(convert_to_exercise_service.files.first).to have_attributes(content: content)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file is binary' do
|
||||
let(:mimetype) { 'image/png' }
|
||||
let(:binary) { true }
|
||||
|
||||
it 'creates an exercise with a file with attachment and the correct attributes' do
|
||||
expect(convert_to_exercise_service.files.first.native_file).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'when usage_by_lms is edit' do
|
||||
let(:usage_by_lms) { 'edit' }
|
||||
|
||||
it 'creates an exercise with a file with correct attributes' do
|
||||
expect(convert_to_exercise_service.files.first).to have_attributes(read_only: false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file is a model-solution-placeholder (needed by proforma until issue #5 is resolved)' do
|
||||
let(:file) { Proforma::TaskFile.new(id: 'ms-placeholder-file') }
|
||||
|
||||
it 'leaves exercise_files empty' do
|
||||
expect(convert_to_exercise_service.files).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when task has a model-solution' do
|
||||
let(:model_solutions) { [model_solution] }
|
||||
let(:model_solution) do
|
||||
Proforma::ModelSolution.new(
|
||||
id: 'ms-id',
|
||||
files: ms_files
|
||||
)
|
||||
end
|
||||
let(:ms_files) { [ms_file] }
|
||||
let(:ms_file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'ms-file',
|
||||
content: 'content',
|
||||
filename: 'filename.txt',
|
||||
used_by_grader: 'used_by_grader',
|
||||
visible: 'yes',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'reference_implementation'
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates an exercise with a file with role Reference Implementation' do
|
||||
expect(convert_to_exercise_service.files.first).to have_attributes(
|
||||
role: 'reference_implementation'
|
||||
)
|
||||
end
|
||||
|
||||
context 'when task has two model-solutions' do
|
||||
let(:model_solutions) { [model_solution, model_solution2] }
|
||||
let(:model_solution2) do
|
||||
Proforma::ModelSolution.new(
|
||||
id: 'ms-id-2',
|
||||
files: ms_files_2
|
||||
)
|
||||
end
|
||||
let(:ms_files_2) { [ms_file_2] }
|
||||
let(:ms_file_2) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'ms-file-2',
|
||||
content: 'content',
|
||||
filename: 'filename.txt',
|
||||
used_by_grader: 'used_by_grader',
|
||||
visible: 'yes',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'reference_implementation'
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates an exercise with two files with role Reference Implementation' do
|
||||
expect(convert_to_exercise_service.files).to have(2).items.and(all(have_attributes(role: 'reference_implementation')))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when task has a test' do
|
||||
let(:tests) { [test] }
|
||||
let(:test) do
|
||||
Proforma::Test.new(
|
||||
id: 'test-id',
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
internal_description: 'internal_description',
|
||||
test_type: 'test_type',
|
||||
files: test_files,
|
||||
meta_data: {
|
||||
'feedback-message' => 'feedback-message',
|
||||
'testing-framework' => 'testing-framework',
|
||||
'testing-framework-version' => 'testing-framework-version'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let(:test_files) { [test_file] }
|
||||
let(:test_file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'test_file_id',
|
||||
content: 'testfile-content',
|
||||
filename: 'testfile.txt',
|
||||
used_by_grader: 'yes',
|
||||
visible: 'no',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'teacher_defined_test'
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates an exercise with a test' do
|
||||
expect(convert_to_exercise_service.files.select { |file| file.role == 'teacher_defined_test' }).to have(1).item
|
||||
end
|
||||
|
||||
it 'creates an exercise with a test with correct attributes' do
|
||||
expect(convert_to_exercise_service.files.select { |file| file.role == 'teacher_defined_test' }.first).to have_attributes(
|
||||
feedback_message: 'feedback-message',
|
||||
content: 'testfile-content',
|
||||
name: 'testfile',
|
||||
role: 'teacher_defined_test',
|
||||
hidden: true,
|
||||
read_only: true,
|
||||
file_type: be_a(FileType).and(have_attributes(file_extension: '.txt'))
|
||||
)
|
||||
end
|
||||
|
||||
context 'when task has multiple tests' do
|
||||
let(:tests) { [test, test2] }
|
||||
let(:test2) do
|
||||
Proforma::Test.new(
|
||||
files: test_files2,
|
||||
meta_data: {
|
||||
'feedback-message' => 'feedback-message',
|
||||
'testing-framework' => 'testing-framework',
|
||||
'testing-framework-version' => 'testing-framework-version'
|
||||
}
|
||||
)
|
||||
end
|
||||
let(:test_files2) { [test_file2] }
|
||||
let(:test_file2) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'test_file_id2',
|
||||
content: 'testfile-content',
|
||||
filename: 'testfile.txt',
|
||||
used_by_grader: 'yes',
|
||||
visible: 'no',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'teacher_defined_test'
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates an exercise with two test' do
|
||||
expect(convert_to_exercise_service.files.select { |file| file.role == 'teacher_defined_test' }).to have(2).items
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise is set' do
|
||||
let(:exercise) do
|
||||
FactoryBot.create(
|
||||
:files,
|
||||
title: 'exercise-title',
|
||||
description: 'exercise-description',
|
||||
instructions: 'exercise-instruction'
|
||||
)
|
||||
end
|
||||
|
||||
before { exercise.reload }
|
||||
|
||||
it 'assigns all values to given exercise' do
|
||||
convert_to_exercise_service.save
|
||||
expect(exercise.reload).to have_attributes(
|
||||
id: exercise.id,
|
||||
title: task.title,
|
||||
description: task.description,
|
||||
instructions: task.internal_description,
|
||||
execution_environment: exercise.execution_environment,
|
||||
uuid: exercise.uuid,
|
||||
user: exercise.user,
|
||||
files: be_empty
|
||||
)
|
||||
end
|
||||
|
||||
it 'does not create a new Exercise on save' do
|
||||
expect { convert_to_exercise_service.save }.not_to change(Exercise, :count)
|
||||
end
|
||||
|
||||
context 'with file, model solution and test' do
|
||||
let(:files) { [file] }
|
||||
let(:file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'id',
|
||||
content: 'content',
|
||||
filename: 'filename.txt',
|
||||
used_by_grader: 'used_by_grader',
|
||||
visible: 'yes',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'regular_file'
|
||||
)
|
||||
end
|
||||
let(:tests) { [test] }
|
||||
let(:test) do
|
||||
Proforma::Test.new(
|
||||
id: 'test-id',
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
internal_description: 'regular_file',
|
||||
test_type: 'test_type',
|
||||
files: test_files,
|
||||
meta_data: {
|
||||
'feedback-message' => 'feedback-message',
|
||||
'testing-framework' => 'testing-framework',
|
||||
'testing-framework-version' => 'testing-framework-version'
|
||||
}
|
||||
)
|
||||
end
|
||||
let(:test_files) { [test_file] }
|
||||
let(:test_file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'test_file_id',
|
||||
content: 'testfile-content',
|
||||
filename: 'testfile.txt',
|
||||
used_by_grader: 'yes',
|
||||
visible: 'no',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'teacher_defined_test'
|
||||
)
|
||||
end
|
||||
let(:model_solutions) { [model_solution] }
|
||||
let(:model_solution) do
|
||||
Proforma::ModelSolution.new(
|
||||
id: 'ms-id',
|
||||
files: ms_files
|
||||
)
|
||||
end
|
||||
let(:ms_files) { [ms_file] }
|
||||
let(:ms_file) do
|
||||
Proforma::TaskFile.new(
|
||||
id: 'ms-file',
|
||||
content: 'ms-content',
|
||||
filename: 'filename.txt',
|
||||
used_by_grader: 'used_by_grader',
|
||||
visible: 'yes',
|
||||
usage_by_lms: 'display',
|
||||
binary: false,
|
||||
internal_description: 'reference_implementation'
|
||||
)
|
||||
end
|
||||
|
||||
it 'assigns all values to given exercise' do
|
||||
expect(convert_to_exercise_service).to have_attributes(
|
||||
id: exercise.id,
|
||||
files: have(3).items
|
||||
.and(include(have_attributes(content: 'ms-content', role: 'reference_implementation')))
|
||||
.and(include(have_attributes(content: 'content', role: 'regular_file')))
|
||||
.and(include(have_attributes(content: 'testfile-content', role: 'teacher_defined_test')))
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
41
spec/services/proforma_service/export_task_spec.rb
Normal file
41
spec/services/proforma_service/export_task_spec.rb
Normal file
@ -0,0 +1,41 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ProformaService::ExportTask do
|
||||
describe '.new' do
|
||||
subject(:export_task) { described_class.new(exercise: exercise) }
|
||||
|
||||
let(:exercise) { FactoryBot.build(:dummy) }
|
||||
|
||||
it 'assigns exercise' do
|
||||
expect(export_task.instance_variable_get(:@exercise)).to be exercise
|
||||
end
|
||||
|
||||
context 'without exercise' do
|
||||
subject(:export_task) { described_class.new }
|
||||
|
||||
it 'assigns exercise' do
|
||||
expect(export_task.instance_variable_get(:@exercise)).to be nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:export_task) { described_class.call(exercise: exercise) }
|
||||
|
||||
let(:task) { Proforma::Task.new }
|
||||
let(:exercise) { FactoryBot.build(:dummy) }
|
||||
let(:exporter) { instance_double('Proforma::Exporter', perform: 'zip') }
|
||||
|
||||
before do
|
||||
allow(ProformaService::ConvertExerciseToTask).to receive(:call).with(exercise: exercise).and_return(task)
|
||||
allow(Proforma::Exporter).to receive(:new).with(task).and_return(exporter)
|
||||
end
|
||||
|
||||
it do
|
||||
export_task
|
||||
expect(exporter).to have_received(:perform)
|
||||
end
|
||||
end
|
||||
end
|
190
spec/services/proforma_service/import_spec.rb
Normal file
190
spec/services/proforma_service/import_spec.rb
Normal file
@ -0,0 +1,190 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe ProformaService::Import do
|
||||
describe '.new' do
|
||||
subject(:import_service) { described_class.new(zip: zip, user: user) }
|
||||
|
||||
let(:zip) { Tempfile.new('proforma_test_zip_file') }
|
||||
let(:user) { FactoryBot.build(:teacher) }
|
||||
|
||||
it 'assigns zip' do
|
||||
expect(import_service.instance_variable_get(:@zip)).to be zip
|
||||
end
|
||||
|
||||
it 'assigns user' do
|
||||
expect(import_service.instance_variable_get(:@user)).to be user
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:import_service) { described_class.call(zip: zip_file, user: import_user) }
|
||||
|
||||
let(:user) { FactoryBot.create(:teacher) }
|
||||
let(:import_user) { user }
|
||||
let(:zip_file) { Tempfile.new('proforma_test_zip_file') }
|
||||
let(:exercise) do
|
||||
FactoryBot.create(:dummy,
|
||||
instructions: 'instruction',
|
||||
execution_environment: execution_environment,
|
||||
files: files + tests,
|
||||
uuid: uuid,
|
||||
user: user)
|
||||
end
|
||||
|
||||
let(:uuid) {}
|
||||
let(:execution_environment) { FactoryBot.build(:java) }
|
||||
let(:files) { [] }
|
||||
let(:tests) { [] }
|
||||
let(:exporter) { ProformaService::ExportTask.call(exercise: exercise.reload).string }
|
||||
|
||||
before do
|
||||
zip_file.write(exporter)
|
||||
zip_file.rewind
|
||||
end
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
|
||||
it 'sets the correct user as owner of the exercise' do
|
||||
expect(import_service.user).to be user
|
||||
end
|
||||
|
||||
it 'sets the uuid' do
|
||||
expect(import_service.uuid).not_to be_blank
|
||||
end
|
||||
|
||||
context 'when no exercise exists' do
|
||||
before { exercise.destroy }
|
||||
|
||||
it { is_expected.to be_valid }
|
||||
|
||||
it 'sets the correct user as owner of the exercise' do
|
||||
expect(import_service.user).to be user
|
||||
end
|
||||
|
||||
it 'sets the uuid' do
|
||||
expect(import_service.uuid).not_to be_blank
|
||||
end
|
||||
|
||||
context 'when task has a uuid' do
|
||||
let(:uuid) { SecureRandom.uuid }
|
||||
|
||||
it 'sets the uuid' do
|
||||
expect(import_service.uuid).to eql uuid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a mainfile' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
|
||||
context 'when the mainfile is very large' do
|
||||
let(:file) { FactoryBot.build(:file, content: 'test' * 10**5) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a regular file' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file, role: 'regular_file') }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
|
||||
context 'when file has an attachment' do
|
||||
let(:file) { FactoryBot.build(:file, :image, role: 'regular_file') }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when exercise has a file with role reference implementation' do
|
||||
let(:files) { [file] }
|
||||
let(:file) { FactoryBot.build(:file, role: 'reference_implementation', read_only: true) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
|
||||
context 'when exercise has multiple files with role reference implementation' do
|
||||
let(:files) { FactoryBot.build_list(:file, 2, role: 'reference_implementation', read_only: true) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
|
||||
context 'when exercise has a test' do
|
||||
let(:tests) { [test] }
|
||||
let(:test) { FactoryBot.build(:test_file) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
|
||||
context 'when exercise has multiple tests' do
|
||||
let(:tests) { FactoryBot.build_list(:test_file, 2) }
|
||||
|
||||
it { is_expected.to be_an_equal_exercise_as exercise }
|
||||
end
|
||||
|
||||
# context 'when zip contains multiple tasks' do
|
||||
# let(:exporter) { ProformaService::ExportTasks.call(exercises: [exercise, exercise2]).string }
|
||||
|
||||
# let(:exercise2) do
|
||||
# FactoryBot.create(:dummy,
|
||||
# instruction: 'instruction2',
|
||||
# execution_environment: execution_environment,
|
||||
# exercise_files: [],
|
||||
# tests: [],
|
||||
# user: user)
|
||||
# end
|
||||
|
||||
# it 'imports the exercises from zip containing multiple zips' do
|
||||
# expect(import_service).to all be_an(Exercise)
|
||||
# end
|
||||
|
||||
# it 'imports the zip exactly how they were exported' do
|
||||
# expect(import_service).to all be_an_equal_exercise_as(exercise).or be_an_equal_exercise_as(exercise2)
|
||||
# end
|
||||
|
||||
# context 'when a exercise has files and tests' do
|
||||
# let(:files) { [FactoryBot.build(:file), FactoryBot.build(:file, role: 'regular_file')] }
|
||||
# let(:tests) { FactoryBot.build_list(:codeharbor_test, 2) }
|
||||
|
||||
# it 'imports the zip exactly how the were exported' do
|
||||
# expect(import_service).to all be_an_equal_exercise_as(exercise).or be_an_equal_exercise_as(exercise2)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
context 'when task in zip has a different uuid' do
|
||||
let(:uuid) { SecureRandom.uuid }
|
||||
let(:new_uuid) { SecureRandom.uuid }
|
||||
|
||||
before do
|
||||
exercise.update(uuid: new_uuid)
|
||||
end
|
||||
|
||||
it 'creates a new Exercise' do
|
||||
expect(import_service.id).not_to be exercise.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'when task in zip has the same uuid and nothing has changed' do
|
||||
let(:uuid) { SecureRandom.uuid }
|
||||
|
||||
it 'updates the old Exercise' do
|
||||
expect(import_service.id).to be exercise.id
|
||||
end
|
||||
|
||||
context 'when another user imports the exercise' do
|
||||
let(:import_user) { FactoryBot.create(:teacher) }
|
||||
|
||||
it 'creates a new Exercise' do
|
||||
expect(import_service.id).not_to be exercise.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user