Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fedora 5 support #617

Merged
merged 8 commits into from
Dec 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .docker-stack/valkyrie-development/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
---
version: '3.4'
volumes:
fedora:
fedora4:
fedora5:
db:
solr_repo:
solr_index:
services:
fedora:
image: nulib/fcrepo4
fedora4:
image: nulib/fcrepo4:4.7.5
volumes:
- fedora:/data
- fedora4:/data
ports:
- 8986:8080
fedora5:
image: nulib/fcrepo4:5.0.0-RC-2
volumes:
- fedora5:/data
ports:
- 8996:8080
db:
image: healthcheck/postgres:alpine
volumes:
Expand Down
15 changes: 11 additions & 4 deletions .docker-stack/valkyrie-test/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
---
version: '3.4'
volumes:
fedora:
fedora4:
fedora5:
db:
solr_repo:
solr_index:
services:
fedora:
image: nulib/fcrepo4
fedora4:
image: nulib/fcrepo4:4.7.5
volumes:
- fedora:/data
- fedora4:/data
ports:
- 8988:8080
fedora5:
image: nulib/fcrepo4:5.0.0-RC-2
volumes:
- fedora5:/data
ports:
- 8998:8080
db:
image: healthcheck/postgres:alpine
volumes:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ By default, it is assumed that a Valkyrie repository implementation shall use a
1. Run `rake docker:test:down` to stop the server stack
* The test stack cleans up after itself on exit.

## Fedora 5 Compatibility
When configuring your adapter, include the `fedora_version` parameter in your metadata or storage adapter config. If Fedora requires auth, you can also include that in the URL, e.g.:
```
Valkyrie::Storage::Fedora.new(connection: Ldp::Client.new("http://fedoraAdmin:fedoraAdmin@localhost:8988/rest"), fedora_version: 5)
```

The development and test stacks use fully contained virtual volumes and bind all services to different ports, so they can be running at the same time without issue.

## Get Help
Expand Down
11 changes: 8 additions & 3 deletions lib/valkyrie/persistence/fedora/metadata_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ module Valkyrie::Persistence::Fedora
# schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new(title: RDF::URI("http://bad.com/title"))
# )
class MetadataAdapter
attr_reader :connection, :base_path, :schema
attr_reader :connection, :base_path, :schema, :fedora_version

# @param [Ldp::Client] connection
# @param [String] base_path
# @param [Valkyrie::Persistence::Fedora::PermissiveSchema] schema
def initialize(connection:, base_path: "/", schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new)
# @param [Integer] fedora_version
def initialize(connection:, base_path: "/", schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new, fedora_version:)
@connection = connection
@base_path = base_path
@schema = schema
@fedora_version = fedora_version

warn "[DEPRECATION] `fedora_version` will default to 5 in the next major release." unless fedora_version
end

# Construct the query service object using this adapter
Expand Down Expand Up @@ -56,7 +60,8 @@ def uri_to_id(uri)
# @param [RDF::URI] id the Valkyrie ID
# @return [RDF::URI]
def id_to_uri(id)
RDF::URI("#{connection_prefix}/#{pair_path(id)}/#{CGI.escape(id.to_s)}")
prefix = fedora_version == 5 ? "" : "#{pair_path(id)}/"
RDF::URI("#{connection_prefix}/#{prefix}#{CGI.escape(id.to_s)}")
end

# Generate the pairtree path for a given Valkyrie ID
Expand Down
2 changes: 1 addition & 1 deletion lib/valkyrie/persistence/fedora/query_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def find_parents(resource:)
# @return [Array<RDF::URI>]
def include_uris
[
::RDF::Vocab::Fcrepo4.InboundReferences
adapter.fedora_version == 5 ? "http://fedora.info/definitions/fcrepo#PreferInboundReferences" : ::RDF::Vocab::Fcrepo4.InboundReferences
]
end

Expand Down
11 changes: 8 additions & 3 deletions lib/valkyrie/storage/fedora.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
module Valkyrie::Storage
# Implements the DataMapper Pattern to store binary data in fedora
class Fedora
attr_reader :connection, :base_path
attr_reader :connection, :base_path, :fedora_version
PROTOCOL = 'fedora://'

# @param [Ldp::Client] connection
def initialize(connection:, base_path: "/")
def initialize(connection:, base_path: "/", fedora_version:)
@connection = connection
@base_path = base_path
@fedora_version = fedora_version

warn "[DEPRECATION] `fedora_version` will default to 5 in the next major release." unless fedora_version
end

# @param id [Valkyrie::ID]
Expand All @@ -31,11 +34,13 @@ def find_by(id:)
# @return [Valkyrie::StorageAdapter::StreamFile]
def upload(file:, original_filename:, resource:)
identifier = id_to_uri(resource.id) + '/original'
sha1 = fedora_version == 5 ? "sha" : "sha1"
connection.http.put do |request|
request.url identifier
request.headers['Content-Type'] = file.content_type
request.headers['Content-Disposition'] = "attachment; filename=\"#{original_filename}\""
request.headers['digest'] = "sha1=#{Digest::SHA1.file(file)}"
request.headers['digest'] = "#{sha1}=#{Digest::SHA1.file(file)}"
request.headers['link'] = "<http://www.w3.org/ns/ldp#NonRDFSource>; rel=\"type\""
request.body = file.tempfile.read
end
find_by(id: Valkyrie::ID.new(identifier.to_s.sub(/^.+\/\//, PROTOCOL)))
Expand Down
29 changes: 29 additions & 0 deletions spec/support/fedora_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true
module FedoraHelper
def fedora_adapter_config(base_path:, schema: nil, fedora_version: 4)
port = fedora_version == 4 ? 8988 : 8998
opts = {
base_path: base_path,
connection: ::Ldp::Client.new("http://#{fedora_auth}localhost:#{port}/rest"),
fedora_version: fedora_version
}
opts[:schema] = schema if schema
opts
end

def fedora_auth
"fedoraAdmin:fedoraAdmin@"
end

def wipe_fedora!(base_path:, fedora_version: 4)
Valkyrie::Persistence::Fedora::MetadataAdapter.new(fedora_adapter_config(base_path: base_path, fedora_version: fedora_version)).persister.wipe!
end
end

RSpec.configure do |config|
config.before do
wipe_fedora!(base_path: "test_fed", fedora_version: 4)
wipe_fedora!(base_path: "test_fed", fedora_version: 5)
end
config.include FedoraHelper
end
6 changes: 0 additions & 6 deletions spec/support/wipe_raw_fedora_adapter.rb

This file was deleted.

96 changes: 53 additions & 43 deletions spec/valkyrie/persistence/fedora/metadata_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,66 @@
require 'valkyrie/specs/shared_specs'

RSpec.describe Valkyrie::Persistence::Fedora::MetadataAdapter do
let(:adapter) { described_class.new(connection: ::Ldp::Client.new("http://localhost:8988/rest"), base_path: "test_fed") }
it_behaves_like "a Valkyrie::MetadataAdapter"
[4, 5].each do |fedora_version|
context "fedora #{fedora_version}" do
let(:version) { fedora_version }
let(:adapter) { described_class.new(fedora_adapter_config(base_path: "test_fed", fedora_version: version)) }
it_behaves_like "a Valkyrie::MetadataAdapter"

describe "#schema" do
context "by default" do
specify { expect(adapter.schema).to be_a Valkyrie::Persistence::Fedora::PermissiveSchema }
end
describe "#schema" do
context "by default" do
specify { expect(adapter.schema).to be_a Valkyrie::Persistence::Fedora::PermissiveSchema }
end

context "with a custom schema" do
let(:adapter) { described_class.new(connection: ::Ldp::Client.new("http://localhost:8988/rest"), base_path: "test_fed", schema: "custom-schema") }
specify { expect(adapter.schema).to eq("custom-schema") }
end
end
context "with a custom schema" do
let(:adapter) { described_class.new(fedora_adapter_config(base_path: "test_fed", schema: "custom-schema", fedora_version: version)) }
specify { expect(adapter.schema).to eq("custom-schema") }
end
end

describe "#id_to_uri" do
it "converts ids with a slash" do
id = "test/default"
expect(adapter.id_to_uri(id).to_s).to eq "http://localhost:8988/rest/test_fed/te/st/test%2Fdefault"
end
end
describe "#id_to_uri" do
it "converts ids with a slash" do
id = "test/default"
if adapter.fedora_version == 4

describe "#uri_to_id" do
it "converts ids with a slash" do
uri = adapter.id_to_uri("test/default")
expect(adapter.uri_to_id(uri).to_s).to eq "test/default"
end
end
expect(adapter.id_to_uri(id).to_s).to eq "http://localhost:8988/rest/test_fed/te/st/test%2Fdefault"
else
expect(adapter.id_to_uri(id).to_s).to eq "http://localhost:8998/rest/test_fed/test%2Fdefault"
end
end
end

describe "#pair_path" do
it "creates pairs until the first dash" do
expect(adapter.pair_path('abcdef-ghijkl')).to eq('ab/cd/ef')
end
it "creates pairs until the first slash" do
expect(adapter.pair_path('admin_set/default')).to eq('ad/mi/n_/se/t')
end
end
describe "#uri_to_id" do
it "converts ids with a slash" do
uri = adapter.id_to_uri("test/default")
expect(adapter.uri_to_id(uri).to_s).to eq "test/default"
end
end

describe "#id" do
it "creates an md5 hash from the connection_prefix" do
expected = Digest::MD5.hexdigest adapter.connection_prefix
expect(adapter.id.to_s).to eq expected
end
end
describe "#pair_path" do
it "creates pairs until the first dash" do
expect(adapter.pair_path('abcdef-ghijkl')).to eq('ab/cd/ef')
end
it "creates pairs until the first slash" do
expect(adapter.pair_path('admin_set/default')).to eq('ad/mi/n_/se/t')
end
end

describe "#id" do
it "creates an md5 hash from the connection_prefix" do
expected = Digest::MD5.hexdigest adapter.connection_prefix
expect(adapter.id.to_s).to eq expected
end
end

# rubocop:disable Metrics/LineLength
describe "#standardize_query_result?" do
it "throws a deprecation warning when it's set to false" do
allow(Valkyrie.config).to receive(:standardize_query_result).and_return(false)
expect { adapter.standardize_query_result? }.to output(/Please enable query normalization to avoid inconsistent results between different adapters by adding `standardize_query_results: true` to your environment block in config\/valkyrie.yml. This will be the behavior in Valkyrie 2.0./).to_stderr
# rubocop:disable Metrics/LineLength
describe "#standardize_query_result?" do
it "throws a deprecation warning when it's set to false" do
allow(Valkyrie.config).to receive(:standardize_query_result).and_return(false)
expect { adapter.standardize_query_result? }.to output(/Please enable query normalization to avoid inconsistent results between different adapters by adding `standardize_query_results: true` to your environment block in config\/valkyrie.yml. This will be the behavior in Valkyrie 2.0./).to_stderr
end
end
# rubocop:enable Metrics/LineLength
end
end
# rubocop:enable Metrics/LineLength
end
77 changes: 40 additions & 37 deletions spec/valkyrie/persistence/fedora/persister/model_converter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,46 @@
require 'spec_helper'

RSpec.describe Valkyrie::Persistence::Fedora::Persister::ModelConverter do
let(:adapter) do
Valkyrie::Persistence::Fedora::MetadataAdapter.new(
connection: ::Ldp::Client.new("http://localhost:8988/rest"),
base_path: "test_fed",
schema: schema
)
end

let(:resource) { SampleResource.new(title: "My Title") }
let(:converter) { described_class.new(resource: resource, adapter: adapter) }

before do
class SampleResource < Valkyrie::Resource
include Valkyrie::Resource::AccessControls
attribute :title
end
end

after do
Object.send(:remove_const, :SampleResource)
end

context "with the default schema" do
let(:schema) { Valkyrie::Persistence::Fedora::PermissiveSchema.new }
let(:query) { converter.convert.graph.query(predicate: RDF::URI("http://example.com/predicate/title")) }

it "persists to Fedora using a fake predicate" do
expect(query.first.object.to_s).to eq("My Title")
end
end

context "with a defined schema" do
let(:schema) { Valkyrie::Persistence::Fedora::PermissiveSchema.new(title: ::RDF::Vocab::DC.title) }
let(:query) { converter.convert.graph.query(predicate: ::RDF::Vocab::DC.title) }

it "persists to Fedora using the defined predicate" do
expect(query.first.object.to_s).to eq("My Title")
[4, 5].each do |fedora_version|
context "fedora #{fedora_version}" do
let(:version) { fedora_version }
let(:adapter) do
Valkyrie::Persistence::Fedora::MetadataAdapter.new(
fedora_adapter_config(base_path: "test_fed", schema: schema, fedora_version: version)
)
end

let(:resource) { SampleResource.new(title: "My Title") }
let(:converter) { described_class.new(resource: resource, adapter: adapter) }

before do
class SampleResource < Valkyrie::Resource
include Valkyrie::Resource::AccessControls
attribute :title
end
end

after do
Object.send(:remove_const, :SampleResource)
end

context "with the default schema" do
let(:schema) { Valkyrie::Persistence::Fedora::PermissiveSchema.new }
let(:query) { converter.convert.graph.query(predicate: RDF::URI("http://example.com/predicate/title")) }

it "persists to Fedora using a fake predicate" do
expect(query.first.object.to_s).to eq("My Title")
end
end

context "with a defined schema" do
let(:schema) { Valkyrie::Persistence::Fedora::PermissiveSchema.new(title: ::RDF::Vocab::DC.title) }
let(:query) { converter.convert.graph.query(predicate: ::RDF::Vocab::DC.title) }

it "persists to Fedora using the defined predicate" do
expect(query.first.object.to_s).to eq("My Title")
end
end
end
end
end
Loading