hydra-works 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -22
- data/hydra-works.gemspec +1 -1
- data/lib/hydra/works.rb +10 -0
- data/lib/hydra/works/characterization.rb +15 -17
- data/lib/hydra/works/{models/characterization → characterization}/fits_datastream.rb +3 -5
- data/lib/hydra/works/characterization/fits_mapper.rb +0 -0
- data/lib/hydra/works/characterization/schema/base_schema.rb +1 -5
- data/lib/hydra/works/characterization/schema/image_schema.rb +4 -6
- data/lib/hydra/works/models/concerns/file_set/virus_check.rb +4 -41
- data/lib/hydra/works/services/add_file_to_file_set.rb +18 -11
- data/lib/hydra/works/services/characterization_service.rb +24 -36
- data/lib/hydra/works/services/virus_checker_service.rb +73 -0
- data/lib/hydra/works/version.rb +1 -1
- data/spec/hydra/works/characterization_spec.rb +97 -0
- data/spec/hydra/works/models/concerns/file_set/virus_check_spec.rb +6 -64
- data/spec/hydra/works/services/characterization_service_spec.rb +88 -103
- data/spec/hydra/works/services/virus_checker_service_spec.rb +95 -0
- metadata +12 -12
- data/lib/hydra/works/models/characterization/already_there_strategy.rb +0 -12
- data/lib/hydra/works/models/concerns/file_set/characterization/audio.rb +0 -14
- data/lib/hydra/works/models/concerns/file_set/characterization/base.rb +0 -23
- data/lib/hydra/works/models/concerns/file_set/characterization/document.rb +0 -11
- data/lib/hydra/works/models/concerns/file_set/characterization/image.rb +0 -10
- data/lib/hydra/works/models/concerns/file_set/characterization/video.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95116717ae44d85ac45f788033d74e18f8144df6
|
4
|
+
data.tar.gz: eef16574d1817c0c984474457676997e34af7b17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7fa861ac89d69f55d7e70cf19b88feb0b0a4922eaf003dc703d29a5ba3d0bcbcefeee85888414ce19ea81ca74cc8d35442b1f407e69ce64a956657f6215b7fd
|
7
|
+
data.tar.gz: 1ec0c85363b2f9eebf497bb22ea26ade58ace1508620f07762b0f6d6e4f67b979a2111ab07a7fa8dbbaa61d302f29085faee89a99a2522c04faac35e4e77f4f2
|
data/.rubocop.yml
CHANGED
@@ -12,30 +12,9 @@ AllCops:
|
|
12
12
|
Metrics/LineLength:
|
13
13
|
Enabled: false
|
14
14
|
|
15
|
-
Metrics/CyclomaticComplexity:
|
16
|
-
Exclude:
|
17
|
-
- lib/hydra/works/services/add_file_to_file_set.rb
|
18
|
-
|
19
|
-
Metrics/PerceivedComplexity:
|
20
|
-
Exclude:
|
21
|
-
- lib/hydra/works/services/add_file_to_file_set.rb
|
22
|
-
|
23
|
-
Metrics/MethodLength:
|
24
|
-
Exclude:
|
25
|
-
- lib/hydra/works/services/add_file_to_file_set.rb
|
26
|
-
- lib/hydra/works/models/concerns/file_set/virus_check.rb
|
27
|
-
- lib/hydra/works/models/characterization/fits_datastream.rb
|
28
|
-
|
29
15
|
Metrics/ClassLength:
|
30
16
|
Exclude:
|
31
|
-
- lib/hydra/works/
|
32
|
-
|
33
|
-
Metrics/AbcSize:
|
34
|
-
Exclude:
|
35
|
-
- lib/hydra/works/services/add_file_to_file_set.rb
|
36
|
-
- lib/hydra/works/services/full_text_extraction_service.rb
|
37
|
-
- lib/hydra/works/models/concerns/file_set/mime_types.rb
|
38
|
-
- lib/hydra/works/models/concerns/file_set/virus_check.rb
|
17
|
+
- lib/hydra/works/characterization/fits_datastream.rb
|
39
18
|
|
40
19
|
Style/CollectionMethods:
|
41
20
|
PreferredMethods:
|
data/hydra-works.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency 'hydra-pcdm', '>= 0.
|
21
|
+
spec.add_dependency 'hydra-pcdm', '>= 0.8'
|
22
22
|
spec.add_dependency 'hydra-derivatives', '~> 3.0'
|
23
23
|
spec.add_dependency 'hydra-file_characterization', '~> 0.3', '>= 0.3.3'
|
24
24
|
|
data/lib/hydra/works.rb
CHANGED
@@ -38,10 +38,20 @@ module Hydra
|
|
38
38
|
end
|
39
39
|
|
40
40
|
autoload_under 'services' do
|
41
|
+
autoload :VirusCheckerService
|
41
42
|
autoload :AddFileToFileSet
|
42
43
|
autoload :UploadFileToFileSet
|
43
44
|
autoload :PersistDerivative
|
44
45
|
autoload :CharacterizationService
|
45
46
|
end
|
47
|
+
|
48
|
+
ActiveFedora::WithMetadata::DefaultMetadataClassFactory.file_metadata_schemas +=
|
49
|
+
[
|
50
|
+
Characterization::AudioSchema,
|
51
|
+
Characterization::BaseSchema,
|
52
|
+
Characterization::DocumentSchema,
|
53
|
+
Characterization::ImageSchema,
|
54
|
+
Characterization::VideoSchema
|
55
|
+
]
|
46
56
|
end
|
47
57
|
end
|
@@ -1,10 +1,22 @@
|
|
1
1
|
module Hydra::Works
|
2
2
|
module Characterization
|
3
|
-
extend ActiveSupport::Concern
|
4
3
|
extend ActiveSupport::Autoload
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
class << self
|
6
|
+
attr_accessor :mapper
|
7
|
+
def mapper
|
8
|
+
@mapper ||= mapper_defaults
|
9
|
+
end
|
10
|
+
|
11
|
+
def mapper_defaults
|
12
|
+
{ audio_duration: :duration, audio_sample_rate: :sample_rate, exif_tool_version: :exif_version,
|
13
|
+
file_author: :creator, file_language: :language, file_mime_type: :has_mime_type,
|
14
|
+
video_audio_sample_rate: :sample_rate, video_duration: :duration, video_height: :height,
|
15
|
+
video_sample_rate: :sample_rate, video_width: :width }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
autoload :FitsDatastream, 'hydra/works/characterization/fits_datastream.rb'
|
8
20
|
|
9
21
|
autoload_under 'schema' do
|
10
22
|
autoload :AudioSchema
|
@@ -13,19 +25,5 @@ module Hydra::Works
|
|
13
25
|
autoload :ImageSchema
|
14
26
|
autoload :VideoSchema
|
15
27
|
end
|
16
|
-
|
17
|
-
autoload :Base, 'hydra/works/models/concerns/file_set/characterization/base.rb'
|
18
|
-
autoload :Image, 'hydra/works/models/concerns/file_set/characterization/image.rb'
|
19
|
-
autoload :Document, 'hydra/works/models/concerns/file_set/characterization/document.rb'
|
20
|
-
autoload :Video, 'hydra/works/models/concerns/file_set/characterization/video.rb'
|
21
|
-
autoload :Audio, 'hydra/works/models/concerns/file_set/characterization/audio.rb'
|
22
|
-
|
23
|
-
included do
|
24
|
-
include Base
|
25
|
-
include Image
|
26
|
-
include Audio
|
27
|
-
include Video
|
28
|
-
include Document
|
29
|
-
end
|
30
28
|
end
|
31
29
|
end
|
@@ -148,11 +148,9 @@ module Hydra::Works::Characterization
|
|
148
148
|
builder = Nokogiri::XML::Builder.new do |xml|
|
149
149
|
xml.fits(xmlns: 'http://hul.harvard.edu/ois/xml/ns/fits/fits_output',
|
150
150
|
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
151
|
-
'xsi:schemaLocation' =>
|
152
|
-
|
153
|
-
|
154
|
-
version: '0.6.0',
|
155
|
-
timestamp: '1/25/12 11:04 AM') do
|
151
|
+
'xsi:schemaLocation' => "http://hul.harvard.edu/ois/xml/ns/fits/fits_output
|
152
|
+
http://hul.harvard.edu/ois/xml/xsd/fits/fits_output.xsd",
|
153
|
+
version: '0.6.0', timestamp: '1/25/12 11:04 AM') do
|
156
154
|
xml.identification { xml.identity(toolname: 'FITS') }
|
157
155
|
end
|
158
156
|
end
|
File without changes
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module Hydra::Works::Characterization
|
2
2
|
class BaseSchema < ActiveTriples::Schema
|
3
|
-
property :filename, predicate: RDF::Vocab::EBUCore.filename, multiple: false
|
4
3
|
property :format_label, predicate: RDF::Vocab::PREMIS.hasFormatName
|
5
4
|
property :file_size, predicate: RDF::Vocab::EBUCore.fileSize
|
6
5
|
property :well_formed, predicate: RDF::URI.new("http://projecthydra.org/ns/fits/wellFormed")
|
7
6
|
property :valid, predicate: RDF::URI.new("http://projecthydra.org/ns/fits/valid")
|
8
7
|
property :date_created, predicate: RDF::Vocab::EBUCore.dateCreated
|
9
|
-
property :last_modified, predicate: RDF::Vocab::EBUCore.dateModified
|
10
8
|
property :fits_version, predicate: RDF::Vocab::PREMIS.hasCreatingApplicationVersion
|
11
9
|
property :exif_version, predicate: RDF::Vocab::EXIF.exifVersion
|
12
10
|
property :original_checksum, predicate: RDF::Vocab::NFO.hashValue
|
13
|
-
property :mime_type, predicate: RDF::Vocab::EBUCore.hasMimeType
|
14
|
-
index.as :stored_searchable
|
15
|
-
end
|
11
|
+
property :mime_type, predicate: RDF::Vocab::EBUCore.hasMimeType
|
16
12
|
end
|
17
13
|
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module Hydra::Works::Characterization
|
2
2
|
class ImageSchema < ActiveTriples::Schema
|
3
|
-
property :byte_order, predicate: RDF::URI('http://sweet.jpl.nasa.gov/2.2/reprDataFormat.owl#byteOrder')
|
4
|
-
property :compression, predicate: RDF::URI('http://projecthydra.org/ns/mix/compressionScheme')
|
3
|
+
property :byte_order, predicate: RDF::URI('http://sweet.jpl.nasa.gov/2.2/reprDataFormat.owl#byteOrder')
|
4
|
+
property :compression, predicate: RDF::URI('http://projecthydra.org/ns/mix/compressionScheme')
|
5
5
|
property :height, predicate: RDF::Vocab::EBUCore.height
|
6
6
|
property :width, predicate: RDF::Vocab::EBUCore.width
|
7
|
-
|
8
|
-
# property :height, predicate: RDF::Vocab::EXIF.imageLength, multiple: false
|
9
|
-
property :color_space, predicate: RDF::Vocab::EXIF.colorSpace, multiple: false
|
7
|
+
property :color_space, predicate: RDF::Vocab::EXIF.colorSpace
|
10
8
|
property :profile_name, predicate: RDF::URI('http://projecthydra.org/ns/mix/colorProfileName')
|
11
9
|
property :profile_version, predicate: RDF::URI('http://projecthydra.org/ns/mix/colorProfileVersion')
|
12
|
-
property :orientation, predicate: RDF::Vocab::EXIF.orientation
|
10
|
+
property :orientation, predicate: RDF::Vocab::EXIF.orientation
|
13
11
|
property :color_map, predicate: RDF::URI('http://projecthydra.org/ns/mix/colorMap')
|
14
12
|
property :image_producer, predicate: RDF::Vocab::MARCRelators.pht
|
15
13
|
property :capture_device, predicate: RDF::Vocab::EXIF.model
|
@@ -4,49 +4,12 @@ module Hydra::Works
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
validate :detect_viruses
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
return unless original_file && original_file.new_record?
|
12
|
-
|
13
|
-
path = original_file.is_a?(String) ? original_file : local_path_for_file(original_file)
|
14
|
-
unless defined?(ClamAV)
|
15
|
-
warning "Virus checking disabled, #{path} not checked"
|
16
|
-
return
|
17
|
-
end
|
18
|
-
|
19
|
-
scan_result = ClamAV.instance.scanfile(path)
|
20
|
-
if scan_result == 0
|
21
|
-
true
|
22
|
-
else
|
23
|
-
virus_message = "A virus was found in #{path}: #{scan_result}"
|
24
|
-
warning(virus_message)
|
25
|
-
errors.add(:base, virus_message)
|
7
|
+
def detect_viruses
|
8
|
+
return true unless original_file && original_file.new_record? # We have a new file to check
|
9
|
+
return true unless VirusCheckerService.file_has_virus?(original_file)
|
10
|
+
errors.add(:base, "Failed to verify uploaded file is not a virus")
|
26
11
|
false
|
27
12
|
end
|
28
13
|
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def warning(msg)
|
33
|
-
ActiveFedora::Base.logger.warn msg if ActiveFedora::Base.logger
|
34
|
-
end
|
35
|
-
|
36
|
-
# Returns a path for reading the content of +file+
|
37
|
-
# @param [File] file object to retrieve a path for
|
38
|
-
def local_path_for_file(file)
|
39
|
-
if file.respond_to?(:path)
|
40
|
-
file.path
|
41
|
-
else
|
42
|
-
Tempfile.open('') do |t|
|
43
|
-
t.binmode
|
44
|
-
t.write(file.content.read)
|
45
|
-
file.content.rewind
|
46
|
-
t.close
|
47
|
-
t.path
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
14
|
end
|
52
15
|
end
|
@@ -80,18 +80,25 @@ module Hydra::Works
|
|
80
80
|
# @param [true, false] update_existing when true, try to retrieve existing element before building one
|
81
81
|
def find_or_create_file(type, update_existing)
|
82
82
|
if type.instance_of? Symbol
|
83
|
-
|
84
|
-
fail ArgumentError, "you're attempting to add a file to a file_set using '#{type}' association but the file_set does not have an association called '#{type}''" unless association
|
85
|
-
|
86
|
-
current_file = association.reader if update_existing
|
87
|
-
current_file || association.build
|
83
|
+
find_or_create_file_for_symbol(type, update_existing)
|
88
84
|
else
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
85
|
+
find_or_create_file_for_rdf_uri(type, update_existing)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_or_create_file_for_symbol(type, update_existing)
|
90
|
+
association = file_set.association(type)
|
91
|
+
fail ArgumentError, "you're attempting to add a file to a file_set using '#{type}' association but the file_set does not have an association called '#{type}''" unless association
|
92
|
+
current_file = association.reader if update_existing
|
93
|
+
current_file || association.build
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_or_create_file_for_rdf_uri(type, update_existing)
|
97
|
+
current_file = file_set.filter_files_by_type(type_to_uri(type)).first if update_existing
|
98
|
+
unless current_file
|
99
|
+
file_set.files.build
|
100
|
+
current_file = file_set.files.last
|
101
|
+
Hydra::PCDM::AddTypeToFile.call(current_file, type_to_uri(type))
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
@@ -2,20 +2,22 @@ require 'hydra-file_characterization'
|
|
2
2
|
|
3
3
|
module Hydra::Works
|
4
4
|
class CharacterizationService
|
5
|
-
# @param [
|
6
|
-
# @param [
|
7
|
-
#
|
5
|
+
# @param [Hydra::PCDM::File] object which has properties to recieve characterization values.
|
6
|
+
# @param [String, File] source for characterization to be run on. File object or path on disk.
|
7
|
+
# If none is provided, it will assume the binary content already present on the object.
|
8
8
|
# @param [Hash] options to be passed to characterization. parser_mapping:, parser_class:, tools:
|
9
|
-
def self.run(object, source =
|
9
|
+
def self.run(object, source = nil, options = {})
|
10
10
|
new(object, source, options).characterize
|
11
11
|
end
|
12
12
|
|
13
13
|
attr_accessor :object, :source, :mapping, :parser_class, :tools
|
14
14
|
|
15
15
|
def initialize(object, source, options)
|
16
|
-
@object
|
17
|
-
@source
|
18
|
-
@mapping
|
16
|
+
@object = object
|
17
|
+
@source = source
|
18
|
+
@mapping = options.fetch(:parser_mapping, Hydra::Works::Characterization.mapper)
|
19
|
+
@parser_class = options.fetch(:parser_class, Hydra::Works::Characterization::FitsDatastream)
|
20
|
+
@tools = options.fetch(:ch12n_tool, :fits)
|
19
21
|
end
|
20
22
|
|
21
23
|
# Get given source into form that can be passed to Hydra::FileCharacterization
|
@@ -31,41 +33,27 @@ module Hydra::Works
|
|
31
33
|
|
32
34
|
protected
|
33
35
|
|
34
|
-
#
|
35
|
-
def extract_options(opts)
|
36
|
-
parser_mapping = fetch_or_respond(opts, :parser_mapping) || {}
|
37
|
-
parser_class = fetch_or_respond(opts, :parser_class) || FitsDatastream
|
38
|
-
ch12n_tool = opts.fetch(:ch12n_tool) { :fits }
|
39
|
-
|
40
|
-
[parser_mapping, parser_class, ch12n_tool]
|
41
|
-
end
|
42
|
-
|
43
|
-
def fetch_or_respond(opts, key)
|
44
|
-
opts.fetch(key) { object.send(key) if object.respond_to? key }
|
45
|
-
end
|
46
|
-
|
47
|
-
# @param [String,Symbol,File]
|
48
|
-
# @return content if source is a symbol, File if source is string
|
36
|
+
# @return content of object if source is nil; otherwise, return a File or the source
|
49
37
|
def source_to_content
|
50
|
-
if source.
|
51
|
-
|
52
|
-
|
53
|
-
s = object.send(source)
|
54
|
-
s.respond_to?(:content) ? s.content : s
|
55
|
-
else
|
56
|
-
source
|
57
|
-
end
|
38
|
+
return object.content if source.nil?
|
39
|
+
return File.open(source).read if source.is_a? String
|
40
|
+
source.read
|
58
41
|
end
|
59
42
|
|
60
43
|
def extract_metadata(content)
|
61
|
-
Hydra::FileCharacterization.characterize(content,
|
44
|
+
Hydra::FileCharacterization.characterize(content, file_name, tools) do |cfg|
|
62
45
|
cfg[:fits] = Hydra::Derivatives.fits_path
|
63
46
|
end
|
64
47
|
end
|
65
48
|
|
66
|
-
|
67
|
-
|
68
|
-
|
49
|
+
# Determine the filename to send to Hydra::FileCharacterization. If no source is present,
|
50
|
+
# use the name of the file from the object; otherwise, use the supplied source.
|
51
|
+
def file_name
|
52
|
+
if source
|
53
|
+
source.is_a?(File) ? File.basename(source.path) : File.basename(source)
|
54
|
+
else
|
55
|
+
object.original_name.nil? ? "original_file" : object.original_name
|
56
|
+
end
|
69
57
|
end
|
70
58
|
|
71
59
|
# Use OM to parse metadata
|
@@ -111,8 +99,8 @@ module Hydra::Works
|
|
111
99
|
end
|
112
100
|
|
113
101
|
def append_property_value(property, value)
|
114
|
-
value = object
|
115
|
-
object.send("#{property}=", value)
|
102
|
+
value = object.send(property) + [value]
|
103
|
+
object.send("#{property}=", value.uniq)
|
116
104
|
end
|
117
105
|
end
|
118
106
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Hydra::Works
|
2
|
+
# Responsible for checking if the given file is a virus. Coordinates
|
3
|
+
# with the underlying system virus scanner.
|
4
|
+
class VirusCheckerService
|
5
|
+
attr_accessor :original_file, :system_virus_scanner
|
6
|
+
|
7
|
+
# @api public
|
8
|
+
# @param original_file [String, #path]
|
9
|
+
# @return true if a virus was detected
|
10
|
+
# @return true if anti-virus was not able to run
|
11
|
+
# @return false if the file was scanned and no viruses were found
|
12
|
+
def self.file_has_virus?(original_file)
|
13
|
+
new(original_file).file_has_virus?
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(original_file, system_virus_scanner = default_system_virus_scanner)
|
17
|
+
self.original_file = original_file
|
18
|
+
self.system_virus_scanner = system_virus_scanner
|
19
|
+
end
|
20
|
+
|
21
|
+
# Default behavior is to raise a validation error and halt the save if a virus is found
|
22
|
+
def file_has_virus?
|
23
|
+
path = original_file.is_a?(String) ? original_file : local_path_for_file(original_file)
|
24
|
+
scan_result = system_virus_scanner.call(path)
|
25
|
+
handle_virus_scan_results(path, scan_result)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Stubbing out the behavior of "The Clam" was growing into a rather nasty
|
31
|
+
# challenge. So instead I'm injecting a system scanner. This allows me to
|
32
|
+
# now test the default system scanner in isolation from the general response
|
33
|
+
# to a system scan.
|
34
|
+
def default_system_virus_scanner
|
35
|
+
if defined?(ClamAV)
|
36
|
+
ClamAV.instance.method(:scanfile)
|
37
|
+
else
|
38
|
+
lambda do |_path|
|
39
|
+
:no_anti_virus_was_run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_virus_scan_results(path, scan_result)
|
45
|
+
case scan_result
|
46
|
+
when 0 then return false
|
47
|
+
when 1
|
48
|
+
warning("A virus was found in #{path}: #{scan_result}")
|
49
|
+
true
|
50
|
+
else
|
51
|
+
warning "Virus checking disabled, #{path} not checked"
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def warning(msg)
|
57
|
+
ActiveFedora::Base.logger.warn msg if ActiveFedora::Base.logger
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns a path for reading the content of +file+
|
61
|
+
# @param [File] file object to retrieve a path for
|
62
|
+
def local_path_for_file(file)
|
63
|
+
return file.path if file.respond_to?(:path)
|
64
|
+
Tempfile.open('') do |t|
|
65
|
+
t.binmode
|
66
|
+
t.write(file.content.read)
|
67
|
+
file.content.rewind
|
68
|
+
t.close
|
69
|
+
t.path
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/hydra/works/version.rb
CHANGED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hydra::Works::Characterization do
|
4
|
+
let(:file) { Hydra::PCDM::File.new }
|
5
|
+
|
6
|
+
describe "properties" do
|
7
|
+
subject { file }
|
8
|
+
context "with inhereited terms from ActiveFedora" do
|
9
|
+
it { is_expected.to respond_to(:label) }
|
10
|
+
it { is_expected.to respond_to(:file_name) }
|
11
|
+
it { is_expected.to respond_to(:file_size) }
|
12
|
+
it { is_expected.to respond_to(:date_created) }
|
13
|
+
it { is_expected.to respond_to(:has_mime_type) }
|
14
|
+
it { is_expected.to respond_to(:date_modified) }
|
15
|
+
it { is_expected.to respond_to(:byte_order) }
|
16
|
+
end
|
17
|
+
context "with Base schema" do
|
18
|
+
it { is_expected.to respond_to(:format_label) }
|
19
|
+
it { is_expected.to respond_to(:file_size) }
|
20
|
+
it { is_expected.to respond_to(:well_formed) }
|
21
|
+
it { is_expected.to respond_to(:valid) }
|
22
|
+
it { is_expected.to respond_to(:date_created) }
|
23
|
+
it { is_expected.to respond_to(:fits_version) }
|
24
|
+
it { is_expected.to respond_to(:exif_version) }
|
25
|
+
it { is_expected.to respond_to(:original_checksum) }
|
26
|
+
it { is_expected.to respond_to(:mime_type) }
|
27
|
+
end
|
28
|
+
context "with Image schema" do
|
29
|
+
it { is_expected.to respond_to(:byte_order) }
|
30
|
+
it { is_expected.to respond_to(:compression) }
|
31
|
+
it { is_expected.to respond_to(:height) }
|
32
|
+
it { is_expected.to respond_to(:width) }
|
33
|
+
it { is_expected.to respond_to(:color_space) }
|
34
|
+
it { is_expected.to respond_to(:profile_name) }
|
35
|
+
it { is_expected.to respond_to(:profile_version) }
|
36
|
+
it { is_expected.to respond_to(:orientation) }
|
37
|
+
it { is_expected.to respond_to(:color_map) }
|
38
|
+
it { is_expected.to respond_to(:image_producer) }
|
39
|
+
it { is_expected.to respond_to(:capture_device) }
|
40
|
+
it { is_expected.to respond_to(:scanning_software) }
|
41
|
+
it { is_expected.to respond_to(:gps_timestamp) }
|
42
|
+
it { is_expected.to respond_to(:latitude) }
|
43
|
+
it { is_expected.to respond_to(:longitude) }
|
44
|
+
end
|
45
|
+
context "with Document schema" do
|
46
|
+
it { is_expected.to respond_to(:file_title) }
|
47
|
+
it { is_expected.to respond_to(:creator) }
|
48
|
+
it { is_expected.to respond_to(:page_count) }
|
49
|
+
it { is_expected.to respond_to(:language) }
|
50
|
+
it { is_expected.to respond_to(:word_count) }
|
51
|
+
it { is_expected.to respond_to(:character_count) }
|
52
|
+
it { is_expected.to respond_to(:line_count) }
|
53
|
+
it { is_expected.to respond_to(:character_set) }
|
54
|
+
it { is_expected.to respond_to(:markup_basis) }
|
55
|
+
it { is_expected.to respond_to(:markup_language) }
|
56
|
+
it { is_expected.to respond_to(:paragraph_count) }
|
57
|
+
it { is_expected.to respond_to(:table_count) }
|
58
|
+
it { is_expected.to respond_to(:graphics_count) }
|
59
|
+
end
|
60
|
+
context "with Video schema" do
|
61
|
+
it { is_expected.to respond_to(:height) }
|
62
|
+
it { is_expected.to respond_to(:width) }
|
63
|
+
it { is_expected.to respond_to(:frame_rate) }
|
64
|
+
it { is_expected.to respond_to(:duration) }
|
65
|
+
it { is_expected.to respond_to(:sample_rate) }
|
66
|
+
end
|
67
|
+
context "with Audio schema" do
|
68
|
+
it { is_expected.to respond_to(:bit_depth) }
|
69
|
+
it { is_expected.to respond_to(:channels) }
|
70
|
+
it { is_expected.to respond_to(:data_format) }
|
71
|
+
it { is_expected.to respond_to(:frame_rate) }
|
72
|
+
it { is_expected.to respond_to(:duration) }
|
73
|
+
it { is_expected.to respond_to(:sample_rate) }
|
74
|
+
it { is_expected.to respond_to(:offset) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "::mapper" do
|
79
|
+
let(:mapper_keys) do
|
80
|
+
[
|
81
|
+
:audio_duration,
|
82
|
+
:audio_sample_rate,
|
83
|
+
:exif_tool_version,
|
84
|
+
:file_author,
|
85
|
+
:file_language,
|
86
|
+
:file_mime_type,
|
87
|
+
:video_audio_sample_rate,
|
88
|
+
:video_duration,
|
89
|
+
:video_height,
|
90
|
+
:video_sample_rate,
|
91
|
+
:video_width
|
92
|
+
]
|
93
|
+
end
|
94
|
+
subject { described_class.mapper.keys }
|
95
|
+
it { is_expected.to eq(mapper_keys) }
|
96
|
+
end
|
97
|
+
end
|
@@ -2,37 +2,23 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Hydra::Works::VirusCheck do
|
4
4
|
context "with ClamAV" do
|
5
|
+
subject { FileWithVirusCheck.new }
|
6
|
+
let(:file) { Hydra::PCDM::File.new { |f| f.content = File.new(File.join(fixture_path, 'sample-file.pdf')) } }
|
7
|
+
|
5
8
|
before do
|
6
9
|
class FileWithVirusCheck < ActiveFedora::Base
|
7
10
|
include Hydra::Works::FileSetBehavior
|
8
11
|
include Hydra::Works::VirusCheck
|
9
12
|
end
|
10
|
-
|
11
|
-
def self.instance
|
12
|
-
@instance ||= ClamAV.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def scanfile(path)
|
16
|
-
puts "scanfile: #{path}"
|
17
|
-
end
|
18
|
-
end
|
13
|
+
allow(subject).to receive(:original_file) { file }
|
19
14
|
end
|
20
15
|
after do
|
21
|
-
Object.send(:remove_const, :ClamAV)
|
22
16
|
Object.send(:remove_const, :FileWithVirusCheck)
|
23
17
|
end
|
24
18
|
|
25
|
-
subject { FileWithVirusCheck.new }
|
26
|
-
let(:file) { Hydra::PCDM::File.new { |f| f.content = File.new(File.join(fixture_path, 'sample-file.pdf')) } }
|
27
|
-
|
28
|
-
before do
|
29
|
-
allow(subject).to receive(:original_file) { file }
|
30
|
-
allow(subject).to receive(:warn) # suppress virus warning messages
|
31
|
-
end
|
32
|
-
|
33
19
|
context 'with an infected file' do
|
34
20
|
before do
|
35
|
-
expect(
|
21
|
+
expect(Hydra::Works::VirusCheckerService).to receive(:file_has_virus?).and_return(true)
|
36
22
|
end
|
37
23
|
it 'fails to save' do
|
38
24
|
expect(subject.save).to eq false
|
@@ -44,56 +30,12 @@ describe Hydra::Works::VirusCheck do
|
|
44
30
|
|
45
31
|
context 'with a clean file' do
|
46
32
|
before do
|
47
|
-
expect(ClamAV.instance).to receive(:scanfile).and_return(0)
|
48
33
|
end
|
49
34
|
|
50
35
|
it 'does not detect viruses' do
|
51
|
-
expect(
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context 'with a file that responds to :path' do
|
56
|
-
before do
|
57
|
-
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'gets the filename from :path' do
|
61
|
-
expect(subject.send(:local_path_for_file, file)).to eq('/tmp/file.pdf')
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'original file does not respond to path' do
|
66
|
-
before do
|
67
|
-
allow(file).to receive(:respond_to?).and_call_original
|
68
|
-
allow(file).to receive(:respond_to?).with(:path).and_return(false)
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'reads the content of the original_file' do
|
72
|
-
expect(file.content).to receive(:read)
|
36
|
+
expect(Hydra::Works::VirusCheckerService).to receive(:file_has_virus?).and_return(false)
|
73
37
|
subject.detect_viruses
|
74
38
|
end
|
75
39
|
end
|
76
40
|
end
|
77
|
-
|
78
|
-
context "Without ClamAV" do
|
79
|
-
before do
|
80
|
-
class FileWithVirusCheck < ActiveFedora::Base
|
81
|
-
include Hydra::Works::FileSetBehavior
|
82
|
-
include Hydra::Works::VirusCheck
|
83
|
-
end
|
84
|
-
Object.send(:remove_const, :ClamAV) if defined?(ClamAV)
|
85
|
-
end
|
86
|
-
|
87
|
-
subject { FileWithVirusCheck.new }
|
88
|
-
let(:file) { Hydra::PCDM::File.new { |f| f.content = File.new(File.join(fixture_path, 'sample-file.pdf')) } }
|
89
|
-
|
90
|
-
before do
|
91
|
-
allow(subject).to receive(:original_file) { file }
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'warns if ClamAV is not defined' do
|
95
|
-
expect(subject).to receive(:warning) # .with("Virus checking disabled, sample-file.pdf not checked")
|
96
|
-
expect(subject.detect_viruses).to eq nil
|
97
|
-
end
|
98
|
-
end
|
99
41
|
end
|
@@ -2,37 +2,31 @@ require 'spec_helper'
|
|
2
2
|
require 'support/file_set_helper'
|
3
3
|
|
4
4
|
describe Hydra::Works::CharacterizationService do
|
5
|
-
let(:demo_class) do
|
6
|
-
Class.new(Hydra::Works::FileSet) do
|
7
|
-
include Hydra::Works::Characterization
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
5
|
describe "integration test for characterizing from path on disk." do
|
12
|
-
let(:filename)
|
13
|
-
let(:path_on_disk)
|
14
|
-
let(:
|
6
|
+
let(:filename) { 'sample-file.pdf' }
|
7
|
+
let(:path_on_disk) { File.join(fixture_path, filename) }
|
8
|
+
let(:file) { Hydra::PCDM::File.new }
|
15
9
|
|
16
10
|
before do
|
17
11
|
skip 'external tools not installed for CI environment' if ENV['CI']
|
18
|
-
described_class.run(
|
12
|
+
described_class.run(file, path_on_disk)
|
19
13
|
end
|
20
14
|
|
21
|
-
it 'successfully sets
|
22
|
-
expect(
|
23
|
-
expect(
|
24
|
-
expect(
|
15
|
+
it 'successfully sets the property values' do
|
16
|
+
expect(file.file_size).to eq(["7618"])
|
17
|
+
expect(file.file_title).to eq(["sample-file"])
|
18
|
+
expect(file.page_count).to eq(["1"])
|
25
19
|
# Persist and reload from persistence layer
|
26
|
-
expect(
|
27
|
-
expect(
|
20
|
+
expect(file.save).to be nil
|
21
|
+
expect(file.reload).to be nil
|
28
22
|
# Re-check property values
|
29
|
-
expect(
|
30
|
-
expect(
|
31
|
-
expect(
|
23
|
+
expect(file.file_size).to eq(["7618"])
|
24
|
+
expect(file.file_title).to eq(["sample-file"])
|
25
|
+
expect(file.page_count).to eq(["1"])
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
35
|
-
describe "handling
|
29
|
+
describe "handling strings, files, and Hydra::PCDM::File as sources" do
|
36
30
|
# Stub Hydra::FileCharacterization.characterize
|
37
31
|
let(:characterization) { class_double("Hydra::FileCharacterization").as_stubbed_const }
|
38
32
|
let(:fits_filename) { 'fits_0.8.5_pdf.xml' }
|
@@ -40,131 +34,126 @@ describe Hydra::Works::CharacterizationService do
|
|
40
34
|
let(:filename) { 'sample-file.pdf' }
|
41
35
|
let(:file_content) { IO.read(File.join(fixture_path, filename)) }
|
42
36
|
let(:file) { Hydra::PCDM::File.new { |f| f.content = file_content } }
|
43
|
-
let(:file_set) { demo_class.new(id: 'demo/ch/12/on') }
|
44
37
|
|
45
38
|
before do
|
46
|
-
mock_add_file_to_file_set(file_set, file)
|
47
39
|
allow(characterization).to receive(:characterize).and_return(fits_response)
|
48
40
|
end
|
49
41
|
|
50
|
-
context "
|
51
|
-
it 'calls the
|
52
|
-
expect(
|
53
|
-
described_class.run(
|
42
|
+
context "with the object as the source" do
|
43
|
+
it 'calls the content method of the object.' do
|
44
|
+
expect(file).to receive(:content)
|
45
|
+
described_class.run(file)
|
54
46
|
end
|
55
47
|
|
56
|
-
|
57
|
-
|
58
|
-
|
48
|
+
context "when original_name is not present" do
|
49
|
+
it 'passes the content to characterization.' do
|
50
|
+
expect(Hydra::FileCharacterization).to receive(:characterize).with(file_content, "original_file", :fits)
|
51
|
+
described_class.run(file)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when original_name is present" do
|
56
|
+
before { allow(file).to receive(:original_name).and_return(filename) }
|
57
|
+
it 'passes the content to characterization.' do
|
58
|
+
expect(Hydra::FileCharacterization).to receive(:characterize).with(file_content, filename, :fits)
|
59
|
+
described_class.run(file)
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
62
64
|
context "using a string path as the source." do
|
63
65
|
it 'passes a file with the string as a path to FileCharacterization.' do
|
64
66
|
path_on_disk = File.join(fixture_path, filename)
|
65
|
-
expect(Hydra::FileCharacterization).to receive(:characterize).with(
|
66
|
-
described_class.run(
|
67
|
+
expect(Hydra::FileCharacterization).to receive(:characterize).with(file_content, filename, :fits)
|
68
|
+
described_class.run(file, path_on_disk)
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
70
72
|
context "using a File instance as the source." do
|
71
73
|
it 'passes the File to FileCharacterization.' do
|
72
74
|
file_inst = File.new(File.join(fixture_path, filename))
|
73
|
-
expect(Hydra::FileCharacterization).to receive(:characterize).with(
|
74
|
-
described_class.run(
|
75
|
+
expect(Hydra::FileCharacterization).to receive(:characterize).with(file_content, filename, :fits)
|
76
|
+
described_class.run(file, file_inst)
|
75
77
|
end
|
76
78
|
end
|
77
79
|
end
|
78
80
|
|
79
81
|
context "passing an object that does not have matching properties" do
|
80
|
-
|
82
|
+
let!(:current_schemas) { ActiveFedora::WithMetadata::DefaultMetadataClassFactory.file_metadata_schemas }
|
83
|
+
|
81
84
|
let(:characterization) { class_double("Hydra::FileCharacterization").as_stubbed_const }
|
82
|
-
let(:
|
83
|
-
|
84
|
-
|
85
|
-
let(:
|
86
|
-
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
87
|
-
let(:file_content) { 'dummy content' }
|
88
|
-
let(:file) { Hydra::PCDM::File.new { |f| f.content = file_content } }
|
89
|
-
let(:file_set) { bland_class.new(id: 'base/ch/12/on') }
|
85
|
+
let(:fits_filename) { 'fits_0.8.5_pdf.xml' }
|
86
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
87
|
+
let(:file_content) { 'dummy content' }
|
88
|
+
let(:file) { Hydra::PCDM::File.new { |f| f.content = file_content } }
|
90
89
|
|
91
90
|
before do
|
92
|
-
|
91
|
+
ActiveFedora::WithMetadata::DefaultMetadataClassFactory.file_metadata_schemas = [ActiveFedora::WithMetadata::DefaultSchema]
|
93
92
|
allow(characterization).to receive(:characterize).and_return(fits_response)
|
94
93
|
end
|
94
|
+
after do
|
95
|
+
ActiveFedora::WithMetadata::DefaultMetadataClassFactory.file_metadata_schemas = [current_schemas]
|
96
|
+
end
|
95
97
|
|
96
98
|
it 'does not explode with an error' do
|
97
|
-
expect { described_class.run(
|
99
|
+
expect { described_class.run(file) }.not_to raise_error
|
98
100
|
end
|
99
101
|
end
|
100
102
|
|
101
103
|
describe 'assigned properties.' do
|
102
104
|
# Stub Hydra::FileCharacterization.characterize
|
103
105
|
let(:characterization) { class_double("Hydra::FileCharacterization").as_stubbed_const }
|
104
|
-
let(:file)
|
105
|
-
let(:file_set) { demo_class.new(id: 'prop/er/ti/es') }
|
106
|
+
let(:file) { Hydra::PCDM::File.new }
|
106
107
|
|
107
108
|
before do
|
108
|
-
|
109
|
+
allow(file).to receive(:content).and_return("mocked content")
|
110
|
+
allow(characterization).to receive(:characterize).and_return(fits_response)
|
111
|
+
described_class.run(file)
|
109
112
|
end
|
110
113
|
|
111
114
|
context 'using document metadata' do
|
112
|
-
let(:fits_filename)
|
113
|
-
let(:fits_response)
|
114
|
-
|
115
|
-
before do
|
116
|
-
allow(characterization).to receive(:characterize).and_return(fits_response)
|
117
|
-
described_class.run(file_set)
|
118
|
-
end
|
115
|
+
let(:fits_filename) { 'fits_0.8.5_pdf.xml' }
|
116
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
119
117
|
|
120
118
|
it 'assigns expected values to document properties.' do
|
121
|
-
expect(
|
122
|
-
expect(
|
119
|
+
expect(file.file_title).to eq(["sample-file"])
|
120
|
+
expect(file.page_count).to eq(["1"])
|
123
121
|
end
|
124
122
|
end
|
125
123
|
|
126
124
|
context 'using image metadata' do
|
127
|
-
let(:fits_filename)
|
128
|
-
let(:fits_response)
|
129
|
-
|
130
|
-
allow(characterization).to receive(:characterize).and_return(fits_response)
|
131
|
-
described_class.run(file_set)
|
132
|
-
end
|
125
|
+
let(:fits_filename) { 'fits_0.8.5_jp2.xml' }
|
126
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
127
|
+
|
133
128
|
it 'assigns expected values to image properties.' do
|
134
|
-
expect(
|
135
|
-
expect(
|
136
|
-
expect(
|
137
|
-
expect(
|
138
|
-
expect(
|
139
|
-
expect(
|
129
|
+
expect(file.file_size).to eq(["11043"])
|
130
|
+
expect(file.byte_order).to eq(["big endian"])
|
131
|
+
expect(file.compression).to eq(["JPEG 2000 Lossless", "JPEG 2000"])
|
132
|
+
expect(file.width).to eq(["512"])
|
133
|
+
expect(file.height).to eq(["465"])
|
134
|
+
expect(file.color_space).to eq(["sRGB"])
|
140
135
|
end
|
141
136
|
end
|
142
137
|
context 'using video metadata' do
|
143
|
-
let(:fits_filename)
|
144
|
-
let(:fits_response)
|
145
|
-
|
146
|
-
allow(characterization).to receive(:characterize).and_return(fits_response)
|
147
|
-
described_class.run(file_set)
|
148
|
-
end
|
138
|
+
let(:fits_filename) { 'fits_0.8.5_avi.xml' }
|
139
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
140
|
+
|
149
141
|
it 'assigns expected values to video properties.' do
|
150
|
-
expect(
|
151
|
-
expect(
|
152
|
-
expect(
|
153
|
-
expect(
|
154
|
-
expect(
|
142
|
+
expect(file.height).to eq(["264"])
|
143
|
+
expect(file.width).to eq(["356"])
|
144
|
+
expect(file.duration).to eq(["14.10 s"])
|
145
|
+
expect(file.frame_rate).to eq(["10"])
|
146
|
+
expect(file.sample_rate).to eq(["11025"])
|
155
147
|
end
|
156
148
|
end
|
157
149
|
context 'using audio metadata' do
|
158
|
-
let(:fits_filename)
|
159
|
-
let(:fits_response)
|
160
|
-
|
161
|
-
allow(characterization).to receive(:characterize).and_return(fits_response)
|
162
|
-
described_class.run(file_set)
|
163
|
-
end
|
150
|
+
let(:fits_filename) { 'fits_0.8.5_mp3.xml' }
|
151
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
152
|
+
|
164
153
|
it 'assigns expected values to audio properties.' do
|
165
|
-
expect(
|
166
|
-
expect(
|
167
|
-
expect(
|
154
|
+
expect(file.has_mime_type).to eq(["audio/mpeg"])
|
155
|
+
expect(file.duration).to eq(["0:0:15:261"])
|
156
|
+
expect(file.sample_rate).to eq(["44100"])
|
168
157
|
end
|
169
158
|
end
|
170
159
|
end
|
@@ -172,27 +161,23 @@ describe Hydra::Works::CharacterizationService do
|
|
172
161
|
describe 'assigned properties from fits 0.6.2' do
|
173
162
|
# Stub Hydra::FileCharacterization.characterize
|
174
163
|
let(:characterization) { class_double("Hydra::FileCharacterization").as_stubbed_const }
|
175
|
-
let(:file)
|
176
|
-
let(:file_set) { demo_class.new(id: 'old/pr/op/es') }
|
177
|
-
|
178
|
-
before do
|
179
|
-
mock_add_file_to_file_set(file_set, file)
|
180
|
-
end
|
164
|
+
let(:file) { Hydra::PCDM::File.new }
|
181
165
|
|
182
166
|
context 'using image metadata' do
|
183
|
-
let(:fits_filename)
|
184
|
-
let(:fits_response)
|
167
|
+
let(:fits_filename) { 'fits_0.6.2_jpg.xml' }
|
168
|
+
let(:fits_response) { IO.read(File.join(fixture_path, fits_filename)) }
|
185
169
|
before do
|
170
|
+
allow(file).to receive(:content).and_return("mocked content")
|
186
171
|
allow(characterization).to receive(:characterize).and_return(fits_response)
|
187
|
-
described_class.run(
|
172
|
+
described_class.run(file)
|
188
173
|
end
|
189
174
|
it 'assigns expected values to image properties.' do
|
190
|
-
expect(
|
191
|
-
expect(
|
192
|
-
expect(
|
193
|
-
expect(
|
194
|
-
expect(
|
195
|
-
expect(
|
175
|
+
expect(file.file_size).to eq(["57639"])
|
176
|
+
expect(file.byte_order).to eq(["big endian"])
|
177
|
+
expect(file.compression).to eq(["JPEG (old-style)"])
|
178
|
+
expect(file.width).to eq(["600"])
|
179
|
+
expect(file.height).to eq(["381"])
|
180
|
+
expect(file.color_space).to eq(["YCbCr"])
|
196
181
|
end
|
197
182
|
end
|
198
183
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hydra::Works::VirusCheckerService do
|
4
|
+
let(:system_virus_scanner) { double(call: nil) }
|
5
|
+
let(:file) { Hydra::PCDM::File.new { |f| f.content = File.new(File.join(fixture_path, 'sample-file.pdf')) } }
|
6
|
+
let(:virus_checker) { described_class.new(file, system_virus_scanner) }
|
7
|
+
|
8
|
+
context '.file_has_virus?' do
|
9
|
+
it 'is a convenience method' do
|
10
|
+
mock_object = double(file_has_virus?: true)
|
11
|
+
allow(described_class).to receive(:new).and_return(mock_object)
|
12
|
+
described_class.file_has_virus?(file)
|
13
|
+
expect(mock_object).to have_received(:file_has_virus?)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'with a system virus scanner that did not run' do
|
18
|
+
let(:virus_checker) { described_class.new(file) }
|
19
|
+
it 'will return false and set a system warning' do
|
20
|
+
expect(defined?(ClamAV)).to eq(nil) # A bit of a sanity test to make sure the default behaves
|
21
|
+
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
22
|
+
expect(virus_checker).to receive(:warning).with(kind_of(String))
|
23
|
+
expect(virus_checker.file_has_virus?).to eq(true)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with an infected file' do
|
28
|
+
context 'that responds to :path' do
|
29
|
+
it 'will return false' do
|
30
|
+
expect(system_virus_scanner).to receive(:call).with('/tmp/file.pdf').and_return(1)
|
31
|
+
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
32
|
+
expect(virus_checker.file_has_virus?).to eq(true)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
context 'that does not respond to :path' do
|
36
|
+
it 'will return false' do
|
37
|
+
expect(system_virus_scanner).to receive(:call).with(kind_of(String)).and_return(1)
|
38
|
+
allow(file).to receive(:respond_to?).and_call_original
|
39
|
+
allow(file).to receive(:respond_to?).with(:path).and_return(false)
|
40
|
+
expect(virus_checker.file_has_virus?).to eq(true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a clean file' do
|
46
|
+
context 'that responds to :path' do
|
47
|
+
it 'will return true' do
|
48
|
+
expect(system_virus_scanner).to receive(:call).with('/tmp/file.pdf').and_return(0)
|
49
|
+
allow(file).to receive(:path).and_return('/tmp/file.pdf')
|
50
|
+
expect(virus_checker.file_has_virus?).to eq(false)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context 'that does not respond to :path' do
|
54
|
+
it 'will return true' do
|
55
|
+
expect(system_virus_scanner).to receive(:call).with(kind_of(String)).and_return(0)
|
56
|
+
allow(file).to receive(:respond_to?).and_call_original
|
57
|
+
allow(file).to receive(:respond_to?).with(:path).and_return(false)
|
58
|
+
expect(virus_checker.file_has_virus?).to eq(false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context '#default_system_virus_scanner' do
|
64
|
+
let(:virus_checker) { described_class.new(file) }
|
65
|
+
let(:system_virus_scanner) { virus_checker.send(:default_system_virus_scanner) }
|
66
|
+
it 'is callable' do
|
67
|
+
expect(system_virus_scanner).to respond_to(:call)
|
68
|
+
end
|
69
|
+
context 'when called and ClamAV is NOT defined' do
|
70
|
+
it 'will warn and return :no_anti_virus_was_run if ClamAV is not defined' do
|
71
|
+
expect(system_virus_scanner.call('/tmp/path')).to eq(:no_anti_virus_was_run)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
context 'when called and ClamAV is defined' do
|
75
|
+
before do
|
76
|
+
class ClamAV
|
77
|
+
def self.instance
|
78
|
+
@instance ||= ClamAV.new
|
79
|
+
end
|
80
|
+
|
81
|
+
def scanfile(path)
|
82
|
+
puts "scanfile: #{path}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
after do
|
87
|
+
Object.send(:remove_const, :ClamAV)
|
88
|
+
end
|
89
|
+
it "will call the Clam's scanfile" do
|
90
|
+
expect(ClamAV.instance).to receive(:scanfile).with('/tmp/path')
|
91
|
+
system_virus_scanner.call('/tmp/path')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra-works
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hydra-pcdm
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: hydra-derivatives
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,20 +191,15 @@ files:
|
|
191
191
|
- hydra-works.gemspec
|
192
192
|
- lib/hydra/works.rb
|
193
193
|
- lib/hydra/works/characterization.rb
|
194
|
+
- lib/hydra/works/characterization/fits_datastream.rb
|
195
|
+
- lib/hydra/works/characterization/fits_mapper.rb
|
194
196
|
- lib/hydra/works/characterization/schema/audio_schema.rb
|
195
197
|
- lib/hydra/works/characterization/schema/base_schema.rb
|
196
198
|
- lib/hydra/works/characterization/schema/document_schema.rb
|
197
199
|
- lib/hydra/works/characterization/schema/image_schema.rb
|
198
200
|
- lib/hydra/works/characterization/schema/video_schema.rb
|
199
|
-
- lib/hydra/works/models/characterization/already_there_strategy.rb
|
200
|
-
- lib/hydra/works/models/characterization/fits_datastream.rb
|
201
201
|
- lib/hydra/works/models/collection.rb
|
202
202
|
- lib/hydra/works/models/concerns/collection_behavior.rb
|
203
|
-
- lib/hydra/works/models/concerns/file_set/characterization/audio.rb
|
204
|
-
- lib/hydra/works/models/concerns/file_set/characterization/base.rb
|
205
|
-
- lib/hydra/works/models/concerns/file_set/characterization/document.rb
|
206
|
-
- lib/hydra/works/models/concerns/file_set/characterization/image.rb
|
207
|
-
- lib/hydra/works/models/concerns/file_set/characterization/video.rb
|
208
203
|
- lib/hydra/works/models/concerns/file_set/contained_files.rb
|
209
204
|
- lib/hydra/works/models/concerns/file_set/derivatives.rb
|
210
205
|
- lib/hydra/works/models/concerns/file_set/mime_types.rb
|
@@ -220,6 +215,7 @@ files:
|
|
220
215
|
- lib/hydra/works/services/characterization_service.rb
|
221
216
|
- lib/hydra/works/services/persist_derivative.rb
|
222
217
|
- lib/hydra/works/services/upload_file_to_file_set.rb
|
218
|
+
- lib/hydra/works/services/virus_checker_service.rb
|
223
219
|
- lib/hydra/works/version.rb
|
224
220
|
- lib/hydra/works/vocab/works_terms.rb
|
225
221
|
- solr/config/_rest_managed.json
|
@@ -259,6 +255,7 @@ files:
|
|
259
255
|
- spec/fixtures/test5.mp3
|
260
256
|
- spec/fixtures/updated-file.txt
|
261
257
|
- spec/fixtures/world.png
|
258
|
+
- spec/hydra/works/characterization_spec.rb
|
262
259
|
- spec/hydra/works/models/characterization/fits_datastream_spec.rb
|
263
260
|
- spec/hydra/works/models/collection_spec.rb
|
264
261
|
- spec/hydra/works/models/concerns/file_set/contained_files_spec.rb
|
@@ -272,6 +269,7 @@ files:
|
|
272
269
|
- spec/hydra/works/services/characterization_service_spec.rb
|
273
270
|
- spec/hydra/works/services/persist_derivatives_spec.rb
|
274
271
|
- spec/hydra/works/services/upload_file_spec.rb
|
272
|
+
- spec/hydra/works/services/virus_checker_service_spec.rb
|
275
273
|
- spec/hydra/works_spec.rb
|
276
274
|
- spec/spec_helper.rb
|
277
275
|
- spec/support/file_set_helper.rb
|
@@ -304,7 +302,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
304
302
|
version: '0'
|
305
303
|
requirements: []
|
306
304
|
rubyforge_project:
|
307
|
-
rubygems_version: 2.4
|
305
|
+
rubygems_version: 2.6.4
|
308
306
|
signing_key:
|
309
307
|
specification_version: 4
|
310
308
|
summary: Fundamental repository data model for hydra
|
@@ -330,6 +328,7 @@ test_files:
|
|
330
328
|
- spec/fixtures/test5.mp3
|
331
329
|
- spec/fixtures/updated-file.txt
|
332
330
|
- spec/fixtures/world.png
|
331
|
+
- spec/hydra/works/characterization_spec.rb
|
333
332
|
- spec/hydra/works/models/characterization/fits_datastream_spec.rb
|
334
333
|
- spec/hydra/works/models/collection_spec.rb
|
335
334
|
- spec/hydra/works/models/concerns/file_set/contained_files_spec.rb
|
@@ -343,6 +342,7 @@ test_files:
|
|
343
342
|
- spec/hydra/works/services/characterization_service_spec.rb
|
344
343
|
- spec/hydra/works/services/persist_derivatives_spec.rb
|
345
344
|
- spec/hydra/works/services/upload_file_spec.rb
|
345
|
+
- spec/hydra/works/services/virus_checker_service_spec.rb
|
346
346
|
- spec/hydra/works_spec.rb
|
347
347
|
- spec/spec_helper.rb
|
348
348
|
- spec/support/file_set_helper.rb
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module Hydra::Works::Characterization
|
2
|
-
class AlreadyThereStrategy < ActiveTriples::ExtensionStrategy
|
3
|
-
# override apply method to check if property already exists or reciever already has predicate defined.
|
4
|
-
# Do not add property if the rdf_resource already responds to the property name
|
5
|
-
# Do not add property if the rdf_resource already has a property with the same predicate.
|
6
|
-
def self.apply(resource, property)
|
7
|
-
return if resource.respond_to?(property.name)
|
8
|
-
return if resource.properties.any? { |p| p[1].predicate == property.predicate }
|
9
|
-
resource.property property.name, property.to_h
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Hydra::Works::Characterization
|
2
|
-
module Audio
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
# Apply the audio schema. This will add properties defined in the schema.
|
7
|
-
apply_schema AudioSchema, AlreadyThereStrategy
|
8
|
-
|
9
|
-
# Update the configuration to map the parsed terms to the correct property.
|
10
|
-
parser_mapping.merge!(audio_sample_rate: :sample_rate,
|
11
|
-
audio_duration: :duration)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Hydra::Works::Characterization
|
2
|
-
module Base
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
# Apply the base schema. This will add properties defined in the schema.
|
7
|
-
apply_schema BaseSchema, AlreadyThereStrategy
|
8
|
-
|
9
|
-
# Parser config is :term => :property.
|
10
|
-
# Use this config to override the default behavior of value assignment which is:
|
11
|
-
# value is assigned to the property with the same name as the characterization term.
|
12
|
-
# use parser_config.merge! for subsequent modules.
|
13
|
-
class_attribute :parser_mapping
|
14
|
-
self.parser_mapping = { exif_tool_version: :exif_version,
|
15
|
-
file_mime_type: :mime_type }
|
16
|
-
|
17
|
-
# Parser class is an OM terminology.
|
18
|
-
# It maps the characterization tool's output xml to terms and values.
|
19
|
-
class_attribute :parser_class
|
20
|
-
self.parser_class = FitsDatastream
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
module Hydra::Works::Characterization
|
2
|
-
module Document
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
# Apply the document schema. This will add properties defined in the schema.
|
7
|
-
apply_schema DocumentSchema, AlreadyThereStrategy
|
8
|
-
parser_mapping.merge!(file_author: :creator, file_language: :language)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Hydra::Works::Characterization
|
2
|
-
module Video
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
# Apply the module schema. This will add properties defined in the schema.
|
7
|
-
apply_schema VideoSchema, AlreadyThereStrategy
|
8
|
-
|
9
|
-
# Update the configuration to map the parsed terms to the correct property.
|
10
|
-
parser_mapping.merge!(video_sample_rate: :sample_rate,
|
11
|
-
video_audio_sample_rate: :sample_rate,
|
12
|
-
video_duration: :duration,
|
13
|
-
video_width: :width,
|
14
|
-
video_height: :height)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|