# frozen_string_literal: true require 'spec_helper' require 'fileutils' RSpec.describe AceOfBase::Storage do let(:storage_dir) { Dir.mktmpdir } after { FileUtils.remove_entry(storage_dir, true) } subject { described_class.new(storage_dir) } context "When the storage directory doesn't exist" do before { FileUtils.remove_entry(storage_dir, true) } it 'raises an exception' do expect { subject } .to raise_error(described_class::Error, /does not exist/) end end context 'When the storage directory is not writable' do before { File.chmod(0o400, storage_dir) } after { File.chmod(0o600, storage_dir) } it 'raises an exception' do expect { subject } .to raise_error(described_class::Error, /is not writable/) end end describe '#store' do let(:project) { 'Back To The Future' } let(:shot) { '03' } let(:version) { '32' } let(:status) { 'finished' } let(:finish_date) { '1985-10-26' } let(:internal_bid) { '1.21' } let(:created_date) { '1985-10-26 01:22' } let(:record) { AceOfBase::Record.new([project, shot, version, status, finish_date, internal_bid, created_date]) } let(:target_filename) { Digest::SHA1.hexdigest("#{project}|#{shot}|#{version}") } let(:target_path) { File.join(storage_dir, target_filename) } subject { super().store(record) } it 'creates a new file to store the record in' do expect { subject } .to change { Dir['*', base: storage_dir] } .from([]) .to([target_filename]) end it 'serialises and stores the record' do expect(AceOfBase::RecordSerialiser) .to receive(:encode) .with(record) .and_return('fake contents') subject expect(File.read(target_path)).to eq('fake contents') end context 'When the target file is already locked' do around(:each) do |example| File.open(target_path, 'w') do |file| file.flock(File::LOCK_SH) example.run file.flock(File::LOCK_UN) end end it 'raises an error' do expect { subject } .to raise_error(described_class::Error, /unable .* lock/i) end end context 'When the target file already exists' do let(:previous_data) { 'Great Scott!' } before { File.write(target_path, previous_data) } it 'overwrites the content' do subject expect(File.read(target_path)).not_to eq(previous_data) end end end describe '#load' do let(:project) { 'Back To The Future' } let(:shot) { '03' } let(:version) { '32' } let(:status) { 'finished' } let(:finish_date) { '1985-10-26' } let(:internal_bid) { '1.21' } let(:created_date) { '1985-10-26 01:22' } let(:record) { AceOfBase::Record.new([project, shot, version, status, finish_date, internal_bid, created_date]) } let(:target_filename) { Digest::SHA1.hexdigest("#{project}|#{shot}|#{version}") } let(:target_path) { File.join(storage_dir, target_filename) } let(:content) { AceOfBase::RecordSerialiser.encode(record) } before { File.write(target_path, content) } subject { super().retrieve(project, shot, version) } it { is_expected.to eq(record) } context "When the record doesn't exist" do before { FileUtils.remove_entry(target_path, true) } it 'raises an error' do expect { subject } .to raise_error(described_class::Error, /not found/i) end end end end