hydra-works 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|