Refactoring: Migrate store_test to RSpec.
This commit is contained in:
parent
7e1732e6b9
commit
a8f028164d
8 changed files with 734 additions and 555 deletions
|
@ -122,6 +122,9 @@ RSpec/ContextWording:
|
|||
- 'spec/models/role_spec.rb'
|
||||
- 'spec/models/scheduler_spec.rb'
|
||||
- 'spec/models/smime_certificate_spec.rb'
|
||||
- 'spec/models/store/file_spec.rb'
|
||||
- 'spec/models/store/provider/file_spec.rb'
|
||||
- 'spec/models/store_spec.rb'
|
||||
- 'spec/models/tag/item_spec.rb'
|
||||
- 'spec/models/tag_spec.rb'
|
||||
- 'spec/models/taskbar_spec.rb'
|
||||
|
@ -256,6 +259,9 @@ RSpec/ExampleLength:
|
|||
- 'spec/models/role_spec.rb'
|
||||
- 'spec/models/scheduler_spec.rb'
|
||||
- 'spec/models/sla/has_escalation_calculation_impact_examples.rb'
|
||||
- 'spec/models/store/file_spec.rb'
|
||||
- 'spec/models/store/provider/file_spec.rb'
|
||||
- 'spec/models/store_spec.rb'
|
||||
- 'spec/models/taskbar_spec.rb'
|
||||
- 'spec/models/ticket/article_spec.rb'
|
||||
- 'spec/models/ticket/article/has_ticket_contact_attributes_impact_examples.rb'
|
||||
|
@ -537,6 +543,9 @@ RSpec/MultipleExpectations:
|
|||
- 'spec/models/session_spec.rb'
|
||||
- 'spec/models/sla/has_escalation_calculation_impact_examples.rb'
|
||||
- 'spec/models/smime_certificate_spec.rb'
|
||||
- 'spec/models/store/file_spec.rb'
|
||||
- 'spec/models/store/provider/file_spec.rb'
|
||||
- 'spec/models/store_spec.rb'
|
||||
- 'spec/models/taskbar_spec.rb'
|
||||
- 'spec/models/ticket/article_spec.rb'
|
||||
- 'spec/models/ticket/article/has_ticket_contact_attributes_impact_examples.rb'
|
||||
|
@ -617,6 +626,9 @@ RSpec/NestedGroups:
|
|||
- 'spec/models/channel/driver/twitter_spec.rb'
|
||||
- 'spec/models/channel/email_parser_spec.rb'
|
||||
- 'spec/models/job_spec.rb'
|
||||
- 'spec/models/store/file_spec.rb'
|
||||
- 'spec/models/store/provider/file_spec.rb'
|
||||
- 'spec/models/store_spec.rb'
|
||||
- 'spec/models/token_spec.rb'
|
||||
- 'spec/models/trigger_spec.rb'
|
||||
- 'spec/models/user/has_ticket_create_screen_impact_examples.rb'
|
||||
|
|
|
@ -5,6 +5,8 @@ class Store < ApplicationModel
|
|||
|
||||
belongs_to :store_object, class_name: 'Store::Object', optional: true
|
||||
belongs_to :store_file, class_name: 'Store::File', optional: true
|
||||
delegate :content, to: :store_file
|
||||
delegate :provider, to: :store_file
|
||||
|
||||
validates :filename, presence: true
|
||||
|
||||
|
@ -142,28 +144,6 @@ remove one attachment from storage
|
|||
|
||||
=begin
|
||||
|
||||
get content of file
|
||||
|
||||
store = Store.find(store_id)
|
||||
content_as_string = store.content
|
||||
|
||||
returns
|
||||
|
||||
content_as_string
|
||||
|
||||
=end
|
||||
|
||||
def content
|
||||
file = Store::File.find_by(id: store_file_id)
|
||||
if !file
|
||||
raise "No such file #{store_file_id}!"
|
||||
end
|
||||
|
||||
file.content
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
get content of file in preview size
|
||||
|
||||
store = Store.find(store_id)
|
||||
|
@ -241,15 +221,6 @@ returns
|
|||
slice :id, :filename, :size, :preferences
|
||||
end
|
||||
|
||||
def provider
|
||||
file = Store::File.find_by(id: store_file_id)
|
||||
if !file
|
||||
raise "No such file #{store_file_id}!"
|
||||
end
|
||||
|
||||
file.provider
|
||||
end
|
||||
|
||||
RESIZABLE_MIME_REGEXP = %r{image/(jpeg|jpg|png)}i.freeze
|
||||
|
||||
def self.resizable_mime?(input)
|
||||
|
|
|
@ -78,11 +78,8 @@ in case of fixing sha hash use:
|
|||
|
||||
def self.verify(fix_it = nil)
|
||||
success = true
|
||||
file_ids = Store::File.all.pluck(:id)
|
||||
file_ids.each do |item_id|
|
||||
item = Store::File.find(item_id)
|
||||
content = item.content
|
||||
sha = Digest::SHA256.hexdigest(content)
|
||||
Store::File.find_each(batch_size: 10) do |item|
|
||||
sha = Digest::SHA256.hexdigest(item.content)
|
||||
logger.info "CHECK: Store::File.find(#{item.id})"
|
||||
next if sha == item.sha
|
||||
|
||||
|
@ -90,9 +87,7 @@ in case of fixing sha hash use:
|
|||
logger.error "DIFF: sha diff of Store::File.find(#{item.id}) current:#{sha}/db:#{item.sha}/provider:#{item.provider}"
|
||||
store = Store.find_by(store_file_id: item.id)
|
||||
logger.error "STORE: #{store.inspect}"
|
||||
if fix_it
|
||||
item.update_attribute(:sha, sha) # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
item.update_attribute(:sha, sha) if fix_it # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
success
|
||||
end
|
||||
|
@ -119,26 +114,16 @@ nice move to keep system responsive
|
|||
adapter_source = "Store::Provider::#{source}".constantize
|
||||
adapter_target = "Store::Provider::#{target}".constantize
|
||||
|
||||
file_ids = Store::File.all.pluck(:id)
|
||||
file_ids.each do |item_id|
|
||||
item = Store::File.find(item_id)
|
||||
next if item.provider == target
|
||||
|
||||
content = item.content
|
||||
|
||||
# add to new provider
|
||||
adapter_target.add(content, item.sha)
|
||||
|
||||
# update meta data
|
||||
Store::File.where(provider: source).find_each(batch_size: 10) do |item|
|
||||
adapter_target.add(item.content, item.sha)
|
||||
item.update_attribute(:provider, target) # rubocop:disable Rails/SkipsModelValidations
|
||||
|
||||
# remove from old provider
|
||||
adapter_source.delete(item.sha)
|
||||
|
||||
logger.info "Moved file #{item.sha} from #{source} to #{target}"
|
||||
|
||||
sleep delay if delay
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
|
|
|
@ -4,117 +4,65 @@ class Store::Provider::File
|
|||
|
||||
# write file to fs
|
||||
def self.add(data, sha)
|
||||
|
||||
# install file
|
||||
location = get_location(sha)
|
||||
permission = '600'
|
||||
|
||||
# verify if file already is in file system and if it's not corrupt
|
||||
if File.exist?(location)
|
||||
begin
|
||||
get(sha)
|
||||
rescue
|
||||
delete(sha)
|
||||
end
|
||||
end
|
||||
|
||||
# write file to file system
|
||||
if !File.exist?(location)
|
||||
Rails.logger.debug { "storage write '#{location}' (#{permission})" }
|
||||
file = File.new(location, 'wb')
|
||||
file.write(data)
|
||||
file.close
|
||||
end
|
||||
File.chmod(permission.to_i(8), location)
|
||||
|
||||
# check sha
|
||||
local_sha = Digest::SHA256.hexdigest(get(sha))
|
||||
if sha != local_sha
|
||||
raise "Corrupt file in fs #{location}, sha should be #{sha} but is #{local_sha}"
|
||||
Rails.logger.debug { "storge write '#{location}' (600)" }
|
||||
File.binwrite(location, data)
|
||||
end
|
||||
|
||||
true
|
||||
File.chmod(0o600, location)
|
||||
|
||||
validate_file(sha)
|
||||
rescue # .validate_file will raise an error if contents do not match SHA
|
||||
delete(sha)
|
||||
|
||||
fail_count ||= 0
|
||||
fail_count.zero? ? (fail_count += 1) && retry : raise
|
||||
end
|
||||
|
||||
# read file from fs
|
||||
def self.get(sha)
|
||||
location = get_location(sha)
|
||||
Rails.logger.debug { "read from fs #{location}" }
|
||||
if !File.exist?(location)
|
||||
raise "No such file #{location}"
|
||||
end
|
||||
|
||||
data = File.open(location, 'rb')
|
||||
content = data.read
|
||||
Rails.logger.debug { "read from fs #{location}" }
|
||||
content = File.binread(location)
|
||||
local_sha = Digest::SHA256.hexdigest(content)
|
||||
|
||||
# check sha
|
||||
local_sha = Digest::SHA256.hexdigest(content)
|
||||
if local_sha != sha
|
||||
raise "Corrupt file in fs #{location}, sha should be #{sha} but is #{local_sha}"
|
||||
end
|
||||
raise "File corrupted: path #{location} does not match SHA digest (#{local_sha})" if local_sha != sha
|
||||
|
||||
content
|
||||
end
|
||||
|
||||
class << self
|
||||
alias validate_file get
|
||||
end
|
||||
|
||||
# unlink file from fs
|
||||
def self.delete(sha)
|
||||
location = get_location(sha)
|
||||
|
||||
if File.exist?(location)
|
||||
Rails.logger.info "storage remove '#{location}'"
|
||||
File.delete(location)
|
||||
end
|
||||
|
||||
# check if dir need to be removed
|
||||
locations = location.split('/')
|
||||
(0..locations.count).reverse_each do |count|
|
||||
local_location = locations[0, count].join('/')
|
||||
break if local_location.match?(%r{storage/fs/{0,4}$})
|
||||
break if Dir["#{local_location}/*"].present?
|
||||
next if !Dir.exist?(local_location)
|
||||
# remove empty ancestor directories
|
||||
storage_fs_path = Rails.root.join('storage/fs')
|
||||
location.parent.ascend do |path|
|
||||
break if !Dir.empty?(path)
|
||||
break if path == storage_fs_path
|
||||
|
||||
FileUtils.rmdir(local_location)
|
||||
Dir.rmdir(path)
|
||||
end
|
||||
end
|
||||
|
||||
# generate file location
|
||||
def self.get_location(sha)
|
||||
|
||||
# generate directory
|
||||
base = Rails.root.join('storage/fs').to_s
|
||||
parts = []
|
||||
length1 = 4
|
||||
length2 = 5
|
||||
length3 = 7
|
||||
last_position = 0
|
||||
|
||||
# rubocop:disable Style/CombinableLoops
|
||||
(0..1).each do |_count|
|
||||
end_position = last_position + length1
|
||||
parts.push sha[last_position, length1]
|
||||
last_position = end_position
|
||||
end
|
||||
(0..1).each do |_count|
|
||||
end_position = last_position + length2
|
||||
parts.push sha[last_position, length2]
|
||||
last_position = end_position
|
||||
end
|
||||
(0..1).each do |_count|
|
||||
end_position = last_position + length3
|
||||
parts.push sha[last_position, length3]
|
||||
last_position = end_position
|
||||
end
|
||||
# rubocop:enable Style/CombinableLoops
|
||||
|
||||
path = "#{parts[ 0..6 ].join('/')}/"
|
||||
file = sha[last_position, sha.length]
|
||||
location = "#{base}/#{path}"
|
||||
|
||||
# create directory if not exists
|
||||
if !File.exist?(location)
|
||||
FileUtils.mkdir_p(location)
|
||||
end
|
||||
full_path = location + file
|
||||
full_path.gsub('//', '/')
|
||||
parts = sha.scan(%r{^(.{4})(.{4})(.{5})(.{5})(.{7})(.{7})(.*)}).first
|
||||
Rails.root.join('storage/fs', *parts).tap { |path| FileUtils.mkdir_p(path.parent) }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
95
spec/models/store/file_spec.rb
Normal file
95
spec/models/store/file_spec.rb
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Store::File, type: :model do
|
||||
subject(:file) { described_class.add('foo') }
|
||||
|
||||
describe '.add' do
|
||||
context 'with no preconfigured storage provider' do
|
||||
before { Setting.set('storage_provider', nil) }
|
||||
|
||||
it 'defaults to the "DB" provider' do
|
||||
expect(file.provider).to eq('DB')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a preconfigured storage provider' do
|
||||
before { Setting.set('storage_provider', 'File') }
|
||||
|
||||
after { Store::Provider::File.delete(Digest::SHA256.hexdigest('foo')) }
|
||||
|
||||
it 'defaults to the "DB" provider' do
|
||||
expect(file.provider).to eq('File')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.verify' do
|
||||
context 'when no Store::File records exist' do
|
||||
it 'returns true' do
|
||||
expect(described_class.verify).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all Store::File records have matching #content / #sha attributes' do
|
||||
before do
|
||||
file # create Store::File record
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(described_class.verify).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when at least one Store::File record’s #content / #sha attributes do not match' do
|
||||
before do
|
||||
file # create Store::File record
|
||||
Store::Provider::DB.last.update(data: 'bar')
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(described_class.verify).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.move' do
|
||||
before { Setting.set('storage_provider', nil) }
|
||||
|
||||
after { Store::Provider::File.delete(Digest::SHA256.hexdigest('foo')) }
|
||||
|
||||
let(:storage_path) { Rails.root.join('storage/fs') }
|
||||
|
||||
it 'replaces all Store::Provider::{source} records with Store::Provider::{target} ones' do
|
||||
file # create Store::File record
|
||||
|
||||
expect { described_class.move('DB', 'File') }
|
||||
.to change { file.reload.provider }.to('File')
|
||||
.and change { Store::Provider::DB.count }.by(-1)
|
||||
.and change { Dir[storage_path.join('**', '*')].select { |entry| File.file?(entry) }.count }.by(1)
|
||||
end
|
||||
|
||||
context 'when no Store::File records of the source type exist' do
|
||||
it 'makes no changes and returns true' do
|
||||
file # create Store::File record
|
||||
|
||||
expect { described_class.move('File', 'DB') }
|
||||
.not_to change { file.reload.provider }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when moving from "File" adapter to "DB"' do
|
||||
before { Setting.set('storage_provider', 'File') }
|
||||
|
||||
it 'removes stored files from filesystem' do
|
||||
file # create Store::File record
|
||||
|
||||
expect { described_class.move('File', 'DB') }
|
||||
.to change { file.reload.provider }.to('DB')
|
||||
.and change { Store::Provider::DB.count }.by(1)
|
||||
.and change { Dir[storage_path.join('*')].count }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
124
spec/models/store/provider/file_spec.rb
Normal file
124
spec/models/store/provider/file_spec.rb
Normal file
|
@ -0,0 +1,124 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Store::Provider::File do
|
||||
before { FileUtils.rm_rf(Rails.root.join('storage/fs', sha[0, 4])) }
|
||||
|
||||
after { FileUtils.rm_rf(Rails.root.join('storage/fs', sha[0, 4])) }
|
||||
|
||||
let(:data) { 'foo' }
|
||||
let(:sha) { Digest::SHA256.hexdigest(data) }
|
||||
let(:filepath) { Rails.root.join('storage/fs/2c26/b46b/68ffc/68ff9/9b453c1/d304134/13422d706483bfa0f98a5e886266e7ae') }
|
||||
|
||||
describe '.get_location' do
|
||||
context 'with a valid SHA256 digest' do
|
||||
let(:sha) { '0000111122222333334444444555555566666666666666666666666666666666' }
|
||||
|
||||
it 'returns a Pathname matching the SHA digest (split into chunks of 4, 4, 5, 5, 7, 7, & 32 chars)' do
|
||||
expect(described_class.get_location(sha))
|
||||
.to eq(Rails.root.join('storage/fs/0000/1111/22222/33333/4444444/5555555/66666666666666666666666666666666'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.add' do
|
||||
context 'when no matching file exists' do
|
||||
it 'writes the file to disk' do
|
||||
expect { described_class.add(data, sha) }
|
||||
.to change { File.exist?(filepath) }.to(true)
|
||||
|
||||
expect(File.read(filepath)).to eq(data)
|
||||
end
|
||||
|
||||
it 'sets permissions on the new file to 600' do
|
||||
described_class.add(data, sha)
|
||||
|
||||
expect(File.stat(filepath).mode & 0o777).to eq(0o600)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a matching file exists' do
|
||||
before { FileUtils.mkdir_p(filepath.parent) }
|
||||
|
||||
context 'and its contents match the SHA digest of its filepath' do
|
||||
before do
|
||||
File.write(filepath, 'foo')
|
||||
File.chmod(0o755, filepath)
|
||||
end
|
||||
|
||||
it 'sets file permissions to 600' do
|
||||
expect { described_class.add(data, sha) }
|
||||
.to change { File.stat(filepath).mode & 0o777 }.to(0o600)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and its contents do NOT match the SHA digest of its filepath' do
|
||||
before { File.write(filepath, 'bar') }
|
||||
|
||||
it 'replaces the corrupt file with the specified contents' do
|
||||
expect { described_class.add(data, sha) }
|
||||
.to change { File.read(filepath) }.to('foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.get' do
|
||||
context 'when a file exists for the given SHA digest' do
|
||||
before { FileUtils.mkdir_p(filepath.parent) }
|
||||
|
||||
context 'and its contents match the digest' do
|
||||
before { File.write(filepath, data) }
|
||||
|
||||
it 'returns the contents of the file' do
|
||||
expect(described_class.get(sha)).to eq('foo')
|
||||
end
|
||||
end
|
||||
|
||||
context 'and its contents do NOT match the digest' do
|
||||
before { File.write(filepath, 'bar') }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { described_class.get(sha) }
|
||||
.to raise_error(StandardError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when NO file exists for the given SHA digest' do
|
||||
it 'raises an error' do
|
||||
expect { described_class.get(sha) }
|
||||
.to raise_error(Errno::ENOENT)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.delete' do
|
||||
before do
|
||||
FileUtils.mkdir_p(filepath.parent)
|
||||
File.write(filepath, data)
|
||||
end
|
||||
|
||||
it 'deletes the file' do
|
||||
expect { described_class.delete(sha) }
|
||||
.to change { File.exist?(filepath) }.to(false)
|
||||
end
|
||||
|
||||
context 'when the file’s parent directories contain other files' do
|
||||
before { FileUtils.touch(filepath.parent.join('baz')) }
|
||||
|
||||
it 'leaves non-empty subdirectories in place' do
|
||||
expect { described_class.delete(sha) }
|
||||
.not_to change { Dir.exist?(filepath.parent) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the file’s parent directories contain no other files' do
|
||||
it 'deletes empty parent subdirectories, up to /storage/fs' do
|
||||
expect { described_class.delete(sha) }
|
||||
.to change { Dir.empty?(Rails.root.join('storage/fs')) }.to(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
468
spec/models/store_spec.rb
Normal file
468
spec/models/store_spec.rb
Normal file
|
@ -0,0 +1,468 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
# NOTE: This class uses custom .add & .remove methods
|
||||
# to create and destroy records.
|
||||
# This pattern is a strong candidate for refactoring
|
||||
# to make use of Rails' native ActiveRecord + callbacks functionality.
|
||||
RSpec.describe Store, type: :model do
|
||||
subject(:store) { described_class.add(**attributes) }
|
||||
|
||||
let(:attributes) do
|
||||
{
|
||||
object: 'Test',
|
||||
o_id: 1,
|
||||
data: data,
|
||||
filename: filename,
|
||||
preferences: preferences,
|
||||
created_by_id: 1,
|
||||
}
|
||||
end
|
||||
|
||||
let(:data) { 'hello world' }
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:preferences) { {} }
|
||||
|
||||
describe 'Class methods:' do
|
||||
describe '.add' do
|
||||
it 'creates a new Store record' do
|
||||
expect { described_class.add(**attributes) }.to change(described_class, :count).by(1)
|
||||
end
|
||||
|
||||
it 'returns the newly created Store record' do
|
||||
expect(described_class.add(**attributes)).to eq(described_class.last)
|
||||
end
|
||||
|
||||
it 'saves data to #content attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.content }.to('hello world')
|
||||
end
|
||||
|
||||
it 'saves filename to #filename attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.filename }.to('test.txt')
|
||||
end
|
||||
|
||||
it 'sets #provider attribute to "DB"' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.provider }.to('DB')
|
||||
end
|
||||
|
||||
context 'with UTF-8 (non-ASCII) characters in text' do
|
||||
let(:data) { 'hello world äöüß' }
|
||||
|
||||
it 'stores data as binary string to #content attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.content }.to('hello world äöüß'.force_encoding('ASCII-8BIT'))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with UTF-8 (non-ASCII) characters in filename' do
|
||||
let(:filename) { 'testäöüß.txt' }
|
||||
|
||||
it 'stores filename verbatim to #filename attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.filename }.to('testäöüß.txt')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with binary data' do
|
||||
let(:data) { File.binread(Rails.root.join('test/data/pdf/test1.pdf')) }
|
||||
|
||||
it 'stores data as binary string to #content attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.content&.class }.to(String)
|
||||
.and change { described_class.last&.content }.to(data)
|
||||
end
|
||||
|
||||
it 'saves filename to #filename attribute' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.filename }.to('test.txt')
|
||||
end
|
||||
|
||||
it 'sets #provider attribute to "DB"' do
|
||||
expect { described_class.add(**attributes) }
|
||||
.to change { described_class.last&.provider }.to('DB')
|
||||
end
|
||||
|
||||
context 'when an identical file has been stored before under a different name' do
|
||||
before { described_class.add(**attributes) }
|
||||
|
||||
it 'creates a new (duplicate) described_class record' do
|
||||
expect { described_class.add(**attributes.merge(filename: 'test-again.pdf')) }
|
||||
.to change(described_class, :count).by(1)
|
||||
.and change { described_class.last&.filename }.to('test-again.pdf')
|
||||
.and not_change { described_class.last&.content&.class }
|
||||
.and not_change { described_class.last&.content }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an image (jpeg/jpg/png)' do
|
||||
let(:data) { File.binread(Rails.root.join('test/data/upload/upload2.jpg')) }
|
||||
let(:preferences) { { content_type: 'image/jpg' } }
|
||||
|
||||
it 'generates previews' do
|
||||
described_class.add(**attributes)
|
||||
|
||||
expect(described_class.last.preferences)
|
||||
.to include(resizable: true, content_inline: true, content_preview: true)
|
||||
end
|
||||
|
||||
context 'when system is in import mode' do
|
||||
before { Setting.set('import_mode', true) }
|
||||
|
||||
it 'does not generate previews' do
|
||||
described_class.add(**attributes)
|
||||
|
||||
expect(described_class.last.preferences)
|
||||
.not_to include(resizable: true, content_inline: true, content_preview: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.remove' do
|
||||
before { described_class.add(**attributes) }
|
||||
|
||||
it 'destroys the specified Store record' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.to change(described_class, :count).by(-1)
|
||||
end
|
||||
|
||||
it 'destroys the associated Store::File record' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.to change { described_class::File.count }.by(-1)
|
||||
end
|
||||
|
||||
context 'with the same file stored under multiple o_ids' do
|
||||
before { described_class.add(**attributes.merge(o_id: 2)) }
|
||||
|
||||
it 'destroys only the specified Store record' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.to change(described_class, :count).by(-1)
|
||||
end
|
||||
|
||||
it 'does not destroy the associated Store::File record (because it is referenced by another Store)' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.not_to change { Store::File.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple files stored under the same o_id' do
|
||||
before { described_class.add(**attributes.merge(data: 'bar')) }
|
||||
|
||||
it 'destroys all matching Store records' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.to change(described_class, :count).by(-2)
|
||||
end
|
||||
|
||||
it 'destroys all associated Store::File records' do
|
||||
expect { described_class.remove(object: 'Test', o_id: 1) }
|
||||
.to change { Store::File.count }.by(-2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.list' do
|
||||
let!(:store) do
|
||||
described_class.add(
|
||||
object: 'Test',
|
||||
o_id: 1,
|
||||
data: 'hello world',
|
||||
filename: 'test.txt',
|
||||
preferences: {},
|
||||
created_by_id: 1,
|
||||
)
|
||||
end
|
||||
|
||||
it 'runs a Store.where query for :object / :o_id parameters (:object is Store::Object association name)' do
|
||||
expect(described_class.list(object: 'Test', o_id: 1))
|
||||
.to eq([store])
|
||||
end
|
||||
|
||||
context 'without a Store::Object name' do
|
||||
it 'returns an empty ActiveRecord::Relation' do
|
||||
expect(described_class.list(o_id: 1))
|
||||
.to be_an(ActiveRecord::Relation).and be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a #o_id' do
|
||||
it 'returns an empty ActiveRecord::Relation' do
|
||||
expect(described_class.list(object: 'Test'))
|
||||
.to be_an(ActiveRecord::Relation).and be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Instance methods:' do
|
||||
describe 'image previews (#content_inline / #content_preview)' do
|
||||
let(:attributes) do
|
||||
{
|
||||
object: 'Test',
|
||||
o_id: 1,
|
||||
data: data,
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: content_type,
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
}
|
||||
end
|
||||
|
||||
let(:resized_inline_image) do
|
||||
File.binwrite(temp_file, store.content_inline)
|
||||
Rszr::Image.load(temp_file)
|
||||
end
|
||||
|
||||
let(:resized_preview_image) do
|
||||
File.binwrite(temp_file.next, store.content_preview)
|
||||
Rszr::Image.load(temp_file.next)
|
||||
end
|
||||
|
||||
let(:temp_file) { Tempfile.new.path }
|
||||
|
||||
context 'with content_type: "text/plain"' do
|
||||
let(:content_type) { 'text/plain' }
|
||||
|
||||
context 'and text content' do
|
||||
let(:data) { 'foo' }
|
||||
|
||||
it 'cannot be resized (neither inlined nor previewed)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect { store.content_preview }
|
||||
.to raise_error('Unable to generate preview')
|
||||
|
||||
expect(store.preferences)
|
||||
.to not_include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and not_include(content_preview: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with content_type: "image/*"' do
|
||||
context 'and text content' do
|
||||
let(:content_type) { 'image/jpeg' }
|
||||
let(:data) { 'foo' }
|
||||
|
||||
it 'cannot be resized (neither inlined nor previewed)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect { store.content_preview }
|
||||
.to raise_error('Unable to generate preview')
|
||||
|
||||
expect(store.preferences)
|
||||
.to not_include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and not_include(content_preview: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with image content (width > 1800px)' do
|
||||
context 'width <= 200px' do
|
||||
let(:content_type) { 'image/png' }
|
||||
let(:data) { File.binread(Rails.root.join('test/data/image/1x1.png')) }
|
||||
|
||||
it 'cannot be resized (neither inlined nor previewed)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect { store.content_preview }
|
||||
.to raise_error('Unable to generate preview')
|
||||
|
||||
expect(store.preferences)
|
||||
.to not_include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and not_include(content_preview: true)
|
||||
end
|
||||
end
|
||||
|
||||
context '200px < width <= 1800px)' do
|
||||
let(:content_type) { 'image/png' }
|
||||
let(:data) { File.binread(Rails.root.join('test/data/image/1000x1000.png')) }
|
||||
|
||||
it 'can be resized (previewed but not inlined)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect(resized_preview_image.width).to eq(200)
|
||||
|
||||
expect(store.preferences)
|
||||
.to include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and include(content_preview: true)
|
||||
end
|
||||
end
|
||||
|
||||
context '1800px < width' do
|
||||
let(:content_type) { 'image/jpeg' }
|
||||
let(:data) { File.binread(Rails.root.join('test/data/upload/upload2.jpg')) }
|
||||
|
||||
it 'can be resized (inlined @ 1800px wide or previewed @ 200px wide)' do
|
||||
expect(resized_inline_image.width).to eq(1800)
|
||||
expect(resized_preview_image.width).to eq(200)
|
||||
|
||||
expect(store.preferences)
|
||||
.to include(resizable: true)
|
||||
.and include(content_inline: true)
|
||||
.and include(content_preview: true)
|
||||
end
|
||||
|
||||
context 'kind of wide/short: 8000x300' do
|
||||
let(:data) { File.binread(Rails.root.join('test/data/image/8000x300.jpg')) }
|
||||
|
||||
it 'can be resized (inlined @ 1800px wide or previewed @ 200px wide)' do
|
||||
expect(resized_inline_image.width).to eq(1800)
|
||||
expect(resized_preview_image.width).to eq(200)
|
||||
|
||||
expect(store.preferences)
|
||||
.to include(resizable: true)
|
||||
.and include(content_inline: true)
|
||||
.and include(content_preview: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'very wide/short: 4000x1; i.e., <= 6px vertically per 200px (preview) or 1800px (inline) horizontally' do
|
||||
let(:data) { File.binread(Rails.root.join('test/data/image/4000x1.jpg')) }
|
||||
|
||||
it 'cannot be resized (neither inlined nor previewed)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect { store.content_preview }
|
||||
.to raise_error('Unable to generate preview')
|
||||
|
||||
expect(store.preferences)
|
||||
.to not_include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and not_include(content_preview: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'very wide/short: 8000x25; i.e., <= 6px vertically per 200px (preview) or 1800px (inline) horizontally' do
|
||||
let(:data) { File.binread(Rails.root.join('test/data/image/8000x25.jpg')) }
|
||||
|
||||
it 'cannot be resized (neither inlined nor previewed)' do
|
||||
expect { store.content_inline }
|
||||
.to raise_error('Unable to generate inline')
|
||||
|
||||
expect { store.content_preview }
|
||||
.to raise_error('Unable to generate preview')
|
||||
|
||||
expect(store.preferences)
|
||||
.to not_include(resizable: true)
|
||||
.and not_include(content_inline: true)
|
||||
.and not_include(content_preview: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when preferences exceed storage size' do
|
||||
|
||||
let(:valid_entries) do
|
||||
{
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
}
|
||||
end
|
||||
|
||||
shared_examples 'keeps other entries' do
|
||||
|
||||
context 'when other entries are present' do
|
||||
|
||||
let(:preferences) do
|
||||
super().merge(valid_entries)
|
||||
end
|
||||
|
||||
it 'keeps these entries' do
|
||||
expect(store.preferences).to include(valid_entries)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when single content is oversized' do
|
||||
|
||||
let(:preferences) do
|
||||
{
|
||||
oversized_content: '0' * 2500,
|
||||
}
|
||||
end
|
||||
|
||||
it 'removes that entry' do
|
||||
expect(store.preferences).not_to have_key(:oversized_content)
|
||||
end
|
||||
|
||||
include_examples 'keeps other entries'
|
||||
end
|
||||
|
||||
context 'when the sum of multiple contents is oversized' do
|
||||
|
||||
let(:preferences) do
|
||||
{
|
||||
oversized_content1: '0' * 2000,
|
||||
oversized_content2: '0' * 2000,
|
||||
}
|
||||
end
|
||||
|
||||
it 'removes first entry' do
|
||||
expect(store.preferences).not_to have_key(:oversized_content1)
|
||||
end
|
||||
|
||||
it 'keeps second entry' do
|
||||
expect(store.preferences).to have_key(:oversized_content2)
|
||||
end
|
||||
|
||||
include_examples 'keeps other entries'
|
||||
end
|
||||
|
||||
context 'when single key is oversized' do
|
||||
|
||||
let(:oversized_key) { '0' * 2500 }
|
||||
let(:preferences) do
|
||||
{
|
||||
oversized_key => 'valid content',
|
||||
}
|
||||
end
|
||||
|
||||
it 'removes that entry' do
|
||||
expect(store.preferences).not_to have_key(oversized_key)
|
||||
end
|
||||
|
||||
include_examples 'keeps other entries'
|
||||
end
|
||||
|
||||
context 'when the sum of multiple keys is oversized' do
|
||||
|
||||
let(:oversized_key1) { '0' * 1500 }
|
||||
let(:oversized_key2) { '1' * 1500 }
|
||||
let(:preferences) do
|
||||
{
|
||||
oversized_key1 => 'valid content',
|
||||
oversized_key2 => 'valid content',
|
||||
}
|
||||
end
|
||||
|
||||
it 'removes first entry' do
|
||||
expect(store.preferences).not_to have_key(oversized_key1)
|
||||
end
|
||||
|
||||
it 'keeps second entry' do
|
||||
expect(store.preferences).to have_key(oversized_key2)
|
||||
end
|
||||
|
||||
include_examples 'keeps other entries'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,424 +0,0 @@
|
|||
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class StoreTest < ActiveSupport::TestCase
|
||||
test 'store fs - get_location' do
|
||||
sha = 'ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73'
|
||||
location = Store::Provider::File.get_location(sha)
|
||||
assert_equal(Rails.root.join('storage/fs/ed70/02b4/39e9a/c845f/22357d8/22bac14/44730fbdb6016d3ec9432297b9ec9f73').to_s, location)
|
||||
end
|
||||
|
||||
test 'store fs - empty dir remove' do
|
||||
sha = 'ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73'
|
||||
content = 'content'
|
||||
location = Store::Provider::File.get_location(sha)
|
||||
result = Store::Provider::File.add(content, sha)
|
||||
assert(result)
|
||||
exists = File.exist?(location)
|
||||
assert(exists)
|
||||
Store::Provider::File.delete(sha)
|
||||
exists = File.exist?(location)
|
||||
assert_not(exists)
|
||||
exists = File.exist?(Rails.root.join('storage/fs/ed70/02b4'))
|
||||
assert_not(exists)
|
||||
exists = File.exist?(Rails.root.join('storage/fs/ed70'))
|
||||
assert_not(exists)
|
||||
exists = File.exist?(Rails.root.join('storage/fs'))
|
||||
assert(exists)
|
||||
exists = File.exist?(Rails.root.join('storage'))
|
||||
assert(exists)
|
||||
end
|
||||
|
||||
test 'store attachment and move it between backends' do
|
||||
files = [
|
||||
{
|
||||
data: 'hello world',
|
||||
filename: 'test.txt',
|
||||
o_id: 1,
|
||||
},
|
||||
{
|
||||
data: 'hello world äöüß',
|
||||
filename: 'testäöüß.txt',
|
||||
o_id: 2,
|
||||
},
|
||||
{
|
||||
data: File.binread(Rails.root.join('test/data/pdf/test1.pdf')),
|
||||
filename: 'test.pdf',
|
||||
o_id: 3,
|
||||
},
|
||||
{
|
||||
data: File.binread(Rails.root.join('test/data/pdf/test1.pdf')),
|
||||
filename: 'test-again.pdf',
|
||||
o_id: 4,
|
||||
},
|
||||
]
|
||||
|
||||
files.each do |file|
|
||||
sha = Digest::SHA256.hexdigest(file[:data])
|
||||
|
||||
# add attachments
|
||||
store = Store.add(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
data: file[:data],
|
||||
filename: file[:filename],
|
||||
preferences: {},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert store
|
||||
|
||||
# get list of attachments
|
||||
attachments = Store.list(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
)
|
||||
assert attachments
|
||||
|
||||
# sha check
|
||||
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
|
||||
assert_equal(sha, sha_new, "check file #{file[:filename]}")
|
||||
|
||||
# filename check
|
||||
assert_equal(file[:filename], attachments[0].filename)
|
||||
|
||||
# provider check
|
||||
assert_equal('DB', attachments[0].provider)
|
||||
end
|
||||
|
||||
success = Store::File.verify
|
||||
assert success, 'verify ok'
|
||||
|
||||
Store::File.move('DB', 'File')
|
||||
|
||||
files.each do |file|
|
||||
sha = Digest::SHA256.hexdigest(file[:data])
|
||||
|
||||
# get list of attachments
|
||||
attachments = Store.list(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
)
|
||||
assert attachments
|
||||
|
||||
# sha check
|
||||
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
|
||||
assert_equal(sha, sha_new, "check file #{file[:filename]}")
|
||||
|
||||
# filename check
|
||||
assert_equal(file[:filename], attachments[0].filename)
|
||||
|
||||
# provider check
|
||||
assert_equal('File', attachments[0].provider)
|
||||
end
|
||||
|
||||
success = Store::File.verify
|
||||
assert success, 'verify ok'
|
||||
|
||||
Store::File.move('File', 'DB')
|
||||
|
||||
files.each do |file|
|
||||
sha = Digest::SHA256.hexdigest(file[:data])
|
||||
|
||||
# get list of attachments
|
||||
attachments = Store.list(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
)
|
||||
assert(attachments)
|
||||
assert_equal(attachments.count, 1)
|
||||
|
||||
# sha check
|
||||
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
|
||||
assert_equal(sha, sha_new, "check file #{file[:filename]}")
|
||||
|
||||
# filename check
|
||||
assert_equal(file[:filename], attachments[0].filename)
|
||||
|
||||
# provider check
|
||||
assert_equal('DB', attachments[0].provider)
|
||||
|
||||
# delete attachments
|
||||
success = Store.remove(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
)
|
||||
assert(success)
|
||||
|
||||
# check attachments again
|
||||
attachments = Store.list(
|
||||
object: 'Test',
|
||||
o_id: file[:o_id],
|
||||
)
|
||||
assert_not(attachments[0])
|
||||
end
|
||||
end
|
||||
|
||||
test 'test resizable' do
|
||||
|
||||
# not possible
|
||||
store = Store.add(
|
||||
object: 'SomeObject1',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_not(store.preferences.key?(:resizable))
|
||||
assert_not(store.preferences.key?(:content_inline))
|
||||
assert_not(store.preferences.key?(:content_preview))
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_inline
|
||||
end
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_preview
|
||||
end
|
||||
|
||||
# not possible
|
||||
store = Store.add(
|
||||
object: 'SomeObject2',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal(store.preferences[:resizable], false)
|
||||
assert_not(store.preferences.key?(:content_inline))
|
||||
assert_not(store.preferences.key?(:content_preview))
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_inline
|
||||
end
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_preview
|
||||
end
|
||||
|
||||
# possible (preview and inline)
|
||||
store = Store.add(
|
||||
object: 'SomeObject3',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload2.jpg')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal(store.preferences[:resizable], true)
|
||||
assert_equal(store.preferences[:content_inline], true)
|
||||
assert_equal(store.preferences[:content_preview], true)
|
||||
|
||||
temp_file = ::Tempfile.new.path
|
||||
File.binwrite(temp_file, store.content_inline)
|
||||
image = Rszr::Image.load(temp_file)
|
||||
assert_equal(image.width, 1800)
|
||||
|
||||
temp_file = ::Tempfile.new.path
|
||||
File.binwrite(temp_file, store.content_preview)
|
||||
image = Rszr::Image.load(temp_file)
|
||||
assert_equal(image.width, 200)
|
||||
|
||||
# possible (preview only)
|
||||
store = Store.add(
|
||||
object: 'SomeObject4',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/image/1000x1000.png')),
|
||||
filename: 'test1.png',
|
||||
preferences: {
|
||||
content_type: 'image/png',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal(store.preferences[:resizable], true)
|
||||
assert_nil(store.preferences[:content_inline])
|
||||
assert_equal(store.preferences[:content_preview], true)
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_inline
|
||||
end
|
||||
|
||||
temp_file = ::Tempfile.new.path
|
||||
File.binwrite(temp_file, store.content_preview)
|
||||
image = Rszr::Image.load(temp_file)
|
||||
assert_equal(image.width, 200)
|
||||
|
||||
# no preview or inline needed
|
||||
store = Store.add(
|
||||
object: 'SomeObject5',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/image/1x1.png')),
|
||||
filename: 'test1.png',
|
||||
preferences: {
|
||||
content_type: 'image/png',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_nil(store.preferences[:resizable])
|
||||
assert_nil(store.preferences[:content_inline])
|
||||
assert_nil(store.preferences[:content_preview])
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_inline
|
||||
end
|
||||
assert_raises(RuntimeError) do
|
||||
store.content_preview
|
||||
end
|
||||
|
||||
# no preview or inline needed
|
||||
store = Store.add(
|
||||
object: 'SomeObject6',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/image/4000x1.jpg')),
|
||||
filename: 'test1.jpg',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_nil(store.preferences[:resizable])
|
||||
assert_nil(store.preferences[:content_inline])
|
||||
assert_nil(store.preferences[:content_preview])
|
||||
|
||||
# possible (no preview or inline needed)
|
||||
store = Store.add(
|
||||
object: 'SomeObject7',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/image/8000x25.jpg')),
|
||||
filename: 'test1.jpg',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_nil(store.preferences[:resizable])
|
||||
assert_nil(store.preferences[:content_inline])
|
||||
assert_nil(store.preferences[:content_preview])
|
||||
|
||||
# possible (preview and inline)
|
||||
store = Store.add(
|
||||
object: 'SomeObject8',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/image/8000x300.jpg')),
|
||||
filename: 'test1.jpg',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal(store.preferences[:resizable], true)
|
||||
assert_equal(store.preferences[:content_inline], true)
|
||||
assert_equal(store.preferences[:content_preview], true)
|
||||
|
||||
# possible, but skipped (preview and inline)
|
||||
Setting.set('import_mode', true)
|
||||
store = Store.add(
|
||||
object: 'SomeObject3',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload2.jpg')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'image/jpg',
|
||||
content_id: 234,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_nil(store.preferences[:resizable])
|
||||
assert_nil(store.preferences[:content_inline])
|
||||
assert_nil(store.preferences[:content_preview])
|
||||
end
|
||||
|
||||
test 'test maximal preferences size check with one oversized content' do
|
||||
store = Store.add(
|
||||
object: 'SomeObject1',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
some_key: '0' * 2500,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_not(store.preferences.key?(:some_key))
|
||||
assert(store.preferences.key?(:content_id))
|
||||
assert(store.preferences.key?(:content_type))
|
||||
end
|
||||
|
||||
test 'test maximal preferences size check with two oversized content' do
|
||||
store = Store.add(
|
||||
object: 'SomeObject1',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: {
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
some_key1: '0' * 2000,
|
||||
some_key2: '0' * 2000,
|
||||
},
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_not(store.preferences.key?(:some_key1))
|
||||
assert(store.preferences.key?(:some_key2))
|
||||
assert(store.preferences.key?(:content_id))
|
||||
assert(store.preferences.key?(:content_type))
|
||||
end
|
||||
|
||||
test 'test maximal preferences size check with one oversized key' do
|
||||
preferences = {
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
}
|
||||
some_key1 = '0' * 2500
|
||||
preferences[some_key1] = 'some content'
|
||||
|
||||
store = Store.add(
|
||||
object: 'SomeObject1',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: preferences,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_not(store.preferences.key?(some_key1))
|
||||
assert(store.preferences.key?(:content_id))
|
||||
assert(store.preferences.key?(:content_type))
|
||||
end
|
||||
|
||||
test 'test maximal preferences size check with two oversized key' do
|
||||
preferences = {
|
||||
content_type: 'text/plain',
|
||||
content_id: 234,
|
||||
}
|
||||
some_key1 = '0' * 1500
|
||||
preferences[some_key1] = 'some content'
|
||||
some_key2 = '1' * 1500
|
||||
preferences[some_key2] = 'some content'
|
||||
|
||||
store = Store.add(
|
||||
object: 'SomeObject1',
|
||||
o_id: rand(1_234_567_890),
|
||||
data: File.binread(Rails.root.join('test/data/upload/upload1.txt')),
|
||||
filename: 'test1.pdf',
|
||||
preferences: preferences,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_not(store.preferences.key?(some_key1))
|
||||
assert(store.preferences.key?(some_key2))
|
||||
assert(store.preferences.key?(:content_id))
|
||||
assert(store.preferences.key?(:content_type))
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in a new issue