Commit 55d76ff9 authored by Eugenia Grieff's avatar Eugenia Grieff

Add service to import requirements from csv file

- Add tests
parent 1a6e58aa
# frozen_string_literal: true
module RequirementsManagement
class ImportCsvService
def initialize(user, project, csv_io)
@user = user
@project = project
@csv_io = csv_io
@results = { success: 0, error_lines: [], parse_error: false }
end
def execute
process_csv
email_results_to_user
@results
end
private
def process_csv
csv_data = @csv_io.open(&:read).force_encoding(Encoding::UTF_8)
csv_parsing_params = {
col_sep: detect_col_sep(csv_data.lines.first),
headers: true,
header_converters: :symbol
}
CSV.new(csv_data, csv_parsing_params).each.with_index(2) do |row, line_no|
requirement_attributes = {
title: row[:title],
description: row[:description]
}
requirement = RequirementsManagement::CreateRequirementService.new(@project, @user, requirement_attributes).execute
if requirement.persisted?
@results[:success] += 1
else
@results[:error_lines].push(line_no)
end
end
rescue ArgumentError, CSV::MalformedCSVError
@results[:parse_error] = true
end
def email_results_to_user
Notify.import_requirements_csv_email(@user.id, @project.id, @results).deliver_later
end
def detect_col_sep(header)
if header.include?(",")
","
elsif header.include?(";")
";"
elsif header.include?("\t")
"\t"
else
raise CSV::MalformedCSVError
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe RequirementsManagement::ImportCsvService do
let(:project) { create(:project) }
let(:user) { create(:user) }
subject do
uploader = FileUploader.new(project)
uploader.store!(file)
described_class.new(user, project, uploader).execute
end
describe '#execute' do
context 'when user can create requirements' do
before do
project.add_reporter(user)
stub_licensed_features(requirements: true)
end
context 'invalid file' do
let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
it 'returns invalid file error' do
expect(Notify).to receive_message_chain(:import_requirements_csv_email, :deliver_later)
expect(subject[:success]).to eq(0)
expect(subject[:parse_error]).to eq(true)
end
end
context 'comma delimited file' do
let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
it 'imports CSV without errors' do
expect(Notify).to receive_message_chain(:import_requirements_csv_email, :deliver_later)
expect(subject[:success]).to eq(3)
expect(subject[:error_lines]).to eq([])
expect(subject[:parse_error]).to eq(false)
end
it 'correctly sets the requirement attributes' do
expect { subject }.to change { project.requirements.count }.by 3
expect(project.requirements.reload.last).to have_attributes(
title: 'Title with quote"',
description: 'Description'
)
end
end
context 'tab delimited file with error row' do
let(:file) { fixture_file_upload('spec/fixtures/csv_tab.csv') }
it 'imports CSV with some error rows' do
expect(Notify).to receive_message_chain(:import_requirements_csv_email, :deliver_later)
expect(subject[:success]).to eq(2)
expect(subject[:error_lines]).to eq([3])
expect(subject[:parse_error]).to eq(false)
end
it 'correctly sets the requirement attributes' do
expect { subject }.to change { project.requirements.count }.by 2
expect(project.requirements.reload.last).to have_attributes(
title: 'Hello',
description: 'World'
)
end
end
context 'semicolon delimited file with CRLF' do
let(:file) { fixture_file_upload('spec/fixtures/csv_semicolon.csv') }
it 'imports CSV with a blank row' do
expect(Notify).to receive_message_chain(:import_requirements_csv_email, :deliver_later)
expect(subject[:success]).to eq(3)
expect(subject[:error_lines]).to eq([4])
expect(subject[:parse_error]).to eq(false)
end
it 'correctly sets the requirement attributes' do
expect { subject }.to change { project.requirements.count }.by 3
expect(project.requirements.reload.last).to have_attributes(
title: 'Hello',
description: 'World'
)
end
end
end
context 'when user cannot create requirements' do
let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
it 'raises an exception' do
expect { subject }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
end
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