active_fedora-noid 2.0.0.beta3 → 2.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/Gemfile +12 -12
- data/README.md +38 -15
- data/active_fedora-noid.gemspec +3 -3
- data/app/models/minter_state.rb +0 -16
- data/db/migrate/20161021203429_rename_minter_state_random_to_rand.rb +5 -0
- data/lib/active_fedora/noid.rb +4 -4
- data/lib/active_fedora/noid/config.rb +6 -1
- data/lib/active_fedora/noid/minter.rb +3 -0
- data/lib/active_fedora/noid/minter/base.rb +32 -2
- data/lib/active_fedora/noid/minter/db.rb +25 -10
- data/lib/active_fedora/noid/minter/file.rb +60 -0
- data/lib/active_fedora/noid/service.rb +1 -1
- data/lib/active_fedora/noid/version.rb +1 -1
- data/lib/tasks/noid_tasks.rake +43 -17
- data/spec/models/minter_state_spec.rb +0 -18
- data/spec/support/shared_examples/minter.rb +55 -0
- data/spec/unit/config_spec.rb +65 -4
- data/spec/unit/db_minter_spec.rb +27 -40
- data/spec/unit/file_minter_spec.rb +58 -0
- data/spec/unit/noid_spec.rb +4 -0
- data/spec/unit/service_spec.rb +1 -1
- metadata +15 -11
- data/lib/active_fedora/noid/synchronized_minter.rb +0 -45
- data/spec/unit/synchronized_minter_spec.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 709c8e18225adbbd00041373fc45c436166ffa50
|
4
|
+
data.tar.gz: 4b4a569df3483bf994dc154ed986fc4bf700561c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ad9a677d42550c1fa40545ab19b5f872da006971a73cdbe9cf8788667316da5fee10541779f155d156ba772eca59f79d0a9c7db5262c07bb97e0f0320b506d1
|
7
|
+
data.tar.gz: db77507d045c565b2c7aa1ea351f4112405f0dcbaef0f47081f5589e6a56c2099cb1639dd6fda906ac621ec9a30a4229c3607db728a676674f01fa770159477d
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -6,13 +6,13 @@ gemspec
|
|
6
6
|
group :development, :test do
|
7
7
|
gem 'byebug' unless ENV['CI']
|
8
8
|
gem 'coveralls', require: false
|
9
|
-
gem 'byebug' unless ENV['CI']
|
10
9
|
end
|
10
|
+
|
11
11
|
# BEGIN ENGINE_CART BLOCK
|
12
|
-
# engine_cart: 0.
|
13
|
-
# engine_cart stanza: 0.
|
12
|
+
# engine_cart: 1.0.1
|
13
|
+
# engine_cart stanza: 0.10.0
|
14
14
|
# the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
|
15
|
-
file = File.expand_path(
|
15
|
+
file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', File.dirname(__FILE__)))
|
16
16
|
if File.exist?(file)
|
17
17
|
begin
|
18
18
|
eval_gemfile file
|
@@ -26,19 +26,19 @@ else
|
|
26
26
|
if ENV['RAILS_VERSION']
|
27
27
|
if ENV['RAILS_VERSION'] == 'edge'
|
28
28
|
gem 'rails', github: 'rails/rails'
|
29
|
-
ENV['ENGINE_CART_RAILS_OPTIONS']=
|
29
|
+
ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
|
30
30
|
else
|
31
31
|
gem 'rails', ENV['RAILS_VERSION']
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
gem '
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
gem 'sass-rails',
|
35
|
+
case ENV['RAILS_VERSION']
|
36
|
+
when /^4.2/
|
37
|
+
gem 'responders', '~> 2.0'
|
38
|
+
gem 'sass-rails', '>= 5.0'
|
39
|
+
gem 'coffee-rails', '~> 4.1.0'
|
40
|
+
when /^4.[01]/
|
41
|
+
gem 'sass-rails', '< 5.0'
|
42
42
|
end
|
43
43
|
end
|
44
44
|
# END ENGINE_CART BLOCK
|
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
[![Version](https://badge.fury.io/rb/active_fedora-noid.png)](http://badge.fury.io/rb/active_fedora-noid)
|
2
|
+
[![Build Status](https://travis-ci.org/projecthydra-labs/active_fedora-noid.png?branch=master)](https://travis-ci.org/projecthydra-labs/active_fedora-noid)
|
3
|
+
[![Coverage Status](https://coveralls.io/repos/projecthydra-labs/active_fedora-noid/badge.svg)](https://coveralls.io/r/projecthydra-labs/active_fedora-noid)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/projecthydra-labs/active_fedora-noid/badges/gpa.svg)](https://codeclimate.com/github/projecthydra-labs/active_fedora-noid)
|
5
|
+
[![Dependency Status](https://gemnasium.com/projecthydra-labs/active_fedora-noid.png)](https://gemnasium.com/projecthydra-labs/active_fedora-noid)
|
2
6
|
[![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)
|
3
7
|
[![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md)
|
4
8
|
[![API Docs](http://img.shields.io/badge/API-docs-blue.svg)](http://rubydoc.info/gems/active_fedora-noid)
|
5
|
-
[![Build Status](https://travis-ci.org/projecthydra-labs/active_fedora-noid.png?branch=master)](https://travis-ci.org/projecthydra-labs/active_fedora-noid)
|
6
|
-
[![Dependency Status](https://gemnasium.com/projecthydra-labs/active_fedora-noid.png)](https://gemnasium.com/projecthydra-labs/active_fedora-noid)
|
7
|
-
[![Coverage Status](https://coveralls.io/repos/projecthydra-labs/active_fedora-noid/badge.svg)](https://coveralls.io/r/projecthydra-labs/active_fedora-noid)
|
8
9
|
|
9
10
|
# ActiveFedora::Noid
|
10
11
|
|
@@ -96,18 +97,30 @@ This will make sure your objects have Noid-like identifiers (e.g. `bb22bb22b`) t
|
|
96
97
|
|
97
98
|
## Overriding default behavior
|
98
99
|
|
99
|
-
|
100
|
+
The default minter in ActiveFedora::Noid 2.x is the database-backed minter to better support multi-host production installations that expect a shared database but not necessarily a shared filesystem (e.g., between load-balanced Rails applications).
|
100
101
|
|
101
|
-
|
102
|
+
### Use file-based minter state (for replayability)
|
103
|
+
|
104
|
+
The file-based minter -- which was the default and only minter in 1.x -- creates a Noid and dumps it to a statefile in the /tmp directory. You can override the location or name of this statefile as follows in e.g. `config/initializers/active_fedora-noid.rb`:
|
102
105
|
|
103
106
|
```ruby
|
104
107
|
require 'active_fedora/noid'
|
105
108
|
|
106
109
|
ActiveFedora::Noid.configure do |config|
|
110
|
+
config.minter_class = ActiveFedora::Noid::Minter::File
|
107
111
|
config.statefile = '/var/foo/bar'
|
108
112
|
end
|
109
113
|
```
|
110
114
|
|
115
|
+
**NOTE**: If you switch to a new minter, it will not automatically start with the same state as the old minter. AF::Noid does include a couple of rake tasks for copying state from database-backed minters to file-backed ones and vice versa:
|
116
|
+
|
117
|
+
``` bash
|
118
|
+
# For migrating minter state from a file to a database
|
119
|
+
$ rake active_fedora:noid:migrate:file_to_database
|
120
|
+
# For migrating minter state from a database to a file
|
121
|
+
$ rake active_fedora:noid:migrate:database_to_file
|
122
|
+
```
|
123
|
+
|
111
124
|
### Identifier template
|
112
125
|
|
113
126
|
To override the default identifier pattern -- a nine-character string consisting of two alphanumeric digits, two numeric digits, two alphanumeric digits, two numeric digits, and a check digit -- put the following code in e.g. `config/initializers/active_fedora-noid.rb`:
|
@@ -124,28 +137,38 @@ For more information about the format of Noid patterns, see pages 8-10 of the [N
|
|
124
137
|
|
125
138
|
### Custom minters
|
126
139
|
|
127
|
-
If you don't want your minter's state to be persisted, you may also
|
140
|
+
If you don't want your minter's state to be persisted, you may also write and configure your own minter. First write up a minter class that looks like the following:
|
128
141
|
|
129
142
|
```ruby
|
130
|
-
class MyMinter
|
131
|
-
def
|
132
|
-
#
|
143
|
+
class MyMinter < ActiveFedora::Noid::Minter::Base
|
144
|
+
def valid?(identifier)
|
145
|
+
# return true/false if you care about ids conforming to templates
|
133
146
|
end
|
134
147
|
|
135
|
-
def
|
136
|
-
#
|
148
|
+
def read
|
149
|
+
# return current minter state
|
137
150
|
end
|
138
151
|
|
139
|
-
def
|
140
|
-
#
|
152
|
+
def write!(state)
|
153
|
+
# write a passed-in minter state
|
154
|
+
end
|
155
|
+
|
156
|
+
protected
|
157
|
+
|
158
|
+
def next_id
|
159
|
+
# return the next identifier from the minter
|
141
160
|
end
|
142
161
|
end
|
143
162
|
```
|
144
163
|
|
145
|
-
Then
|
164
|
+
Then add your new minter class to the ActiveFedora::Noid configuration (`config/initializers/active_fedora-noid.rb`):
|
146
165
|
|
147
166
|
```ruby
|
148
|
-
|
167
|
+
require 'active_fedora/noid'
|
168
|
+
|
169
|
+
ActiveFedora::Noid.configure do |config|
|
170
|
+
config.minter_class = MyMinter
|
171
|
+
end
|
149
172
|
```
|
150
173
|
|
151
174
|
And the service will delegate minting and validating to an instance of your customized minter class.
|
data/active_fedora-noid.gemspec
CHANGED
@@ -19,11 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.add_dependency 'active-fedora', '>= 9.7', '< 12'
|
21
21
|
spec.add_dependency 'noid', '~> 0.9'
|
22
|
-
spec.add_dependency 'rails', '>= 4.2.
|
22
|
+
spec.add_dependency 'rails', '>= 4.2.7.1', '< 6'
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.7"
|
25
|
-
spec.add_development_dependency "rake", "~>
|
25
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3.2'
|
27
27
|
spec.add_development_dependency 'sqlite3'
|
28
|
-
spec.add_development_dependency 'engine_cart', '~> 0
|
28
|
+
spec.add_development_dependency 'engine_cart', '~> 1.0'
|
29
29
|
end
|
data/app/models/minter_state.rb
CHANGED
@@ -2,20 +2,4 @@ class MinterState < ActiveRecord::Base
|
|
2
2
|
validates :namespace, presence: true, uniqueness: true
|
3
3
|
validates :template, presence: true
|
4
4
|
validates :template, format: { with: Object.const_get('Noid::Template::VALID_PATTERN'), message: 'value fails regex' }
|
5
|
-
|
6
|
-
# @return [Hash] options for Noid::Minter.new
|
7
|
-
# * template [String] setting the identifier pattern
|
8
|
-
# * seq [Integer] reflecting minter position in sequence
|
9
|
-
# * counters [Array{Hash}] "buckets" each with :current and :max values
|
10
|
-
# * rand [Object] random number generator object
|
11
|
-
def noid_options
|
12
|
-
return nil unless template
|
13
|
-
opts = {
|
14
|
-
:template => template,
|
15
|
-
:seq => seq
|
16
|
-
}
|
17
|
-
opts[:counters] = JSON.parse(counters, :symbolize_names => true) if counters
|
18
|
-
opts[:rand] = Marshal.load(random) if random
|
19
|
-
opts
|
20
|
-
end
|
21
5
|
end
|
data/lib/active_fedora/noid.rb
CHANGED
@@ -2,9 +2,7 @@ require 'active_fedora/noid/version'
|
|
2
2
|
require 'active_fedora/noid/config'
|
3
3
|
require 'active_fedora/noid/engine'
|
4
4
|
require 'active_fedora/noid/service'
|
5
|
-
require 'active_fedora/noid/minter
|
6
|
-
require 'active_fedora/noid/minter/db'
|
7
|
-
require 'active_fedora/noid/synchronized_minter'
|
5
|
+
require 'active_fedora/noid/minter'
|
8
6
|
|
9
7
|
module ActiveFedora
|
10
8
|
module Noid
|
@@ -18,7 +16,9 @@ module ActiveFedora
|
|
18
16
|
end
|
19
17
|
|
20
18
|
def treeify(identifier)
|
21
|
-
|
19
|
+
head = identifier.split('/').first
|
20
|
+
head.gsub!(/#.*/, '')
|
21
|
+
(head.scan(/..?/).first(4) + [identifier]).join('/')
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
module Noid
|
3
3
|
class Config
|
4
|
-
attr_writer :template, :translate_uri_to_id, :translate_id_to_uri,
|
4
|
+
attr_writer :template, :translate_uri_to_id, :translate_id_to_uri,
|
5
|
+
:statefile, :namespace, :minter_class
|
5
6
|
|
6
7
|
def template
|
7
8
|
@template ||= '.reeddeeddk'
|
@@ -15,6 +16,10 @@ module ActiveFedora
|
|
15
16
|
@namespace ||= 'default'
|
16
17
|
end
|
17
18
|
|
19
|
+
def minter_class
|
20
|
+
@minter_class ||= Minter::Db
|
21
|
+
end
|
22
|
+
|
18
23
|
def translate_uri_to_id
|
19
24
|
lambda do |uri|
|
20
25
|
uri.to_s.sub(baseurl, '').split('/', baseparts).last
|
@@ -1,13 +1,23 @@
|
|
1
1
|
require 'noid'
|
2
|
+
require 'active_fedora'
|
2
3
|
|
3
4
|
module ActiveFedora
|
4
5
|
module Noid
|
5
6
|
module Minter
|
6
7
|
class Base < ::Noid::Minter
|
8
|
+
##
|
9
|
+
# @param template [#to_s] a NOID template
|
10
|
+
#
|
11
|
+
# @see Noid::Template
|
7
12
|
def initialize(template = default_template)
|
8
|
-
super(:
|
13
|
+
super(template: template.to_s)
|
9
14
|
end
|
10
15
|
|
16
|
+
##
|
17
|
+
# Sychronously mint a new identifier. Guarantees the ID is not
|
18
|
+
# already reserved in ActiveFedora.
|
19
|
+
#
|
20
|
+
# @return [String] the minted identifier
|
11
21
|
def mint
|
12
22
|
Mutex.new.synchronize do
|
13
23
|
while true
|
@@ -17,14 +27,34 @@ module ActiveFedora
|
|
17
27
|
end
|
18
28
|
end
|
19
29
|
|
30
|
+
##
|
31
|
+
# @return [Hash] an object representing the current minter state
|
32
|
+
def read
|
33
|
+
raise NotImplementedError.new('Implement #read in child class')
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Updates the minter state to that of the `minter` parameter.
|
38
|
+
#
|
39
|
+
# @param minter [Minter::Base]
|
40
|
+
#
|
41
|
+
# @return [void]
|
42
|
+
def write!(_)
|
43
|
+
raise NotImplementedError.new('Implement #write! in child class')
|
44
|
+
end
|
45
|
+
|
20
46
|
protected
|
21
47
|
|
48
|
+
##
|
49
|
+
# @return [#to_s] the default template for this
|
22
50
|
def default_template
|
23
51
|
ActiveFedora::Noid.config.template
|
24
52
|
end
|
25
53
|
|
54
|
+
##
|
55
|
+
# @return [String] a new identifier.
|
26
56
|
def next_id
|
27
|
-
raise NotImplementedError.new('Implement next_id in child class')
|
57
|
+
raise NotImplementedError.new('Implement #next_id in child class')
|
28
58
|
end
|
29
59
|
end
|
30
60
|
end
|
@@ -4,6 +4,22 @@ module ActiveFedora
|
|
4
4
|
module Noid
|
5
5
|
module Minter
|
6
6
|
class Db < Base
|
7
|
+
|
8
|
+
def read
|
9
|
+
filtered_hash = instance.as_json.select { |key| ['template', 'counters', 'seq', 'rand', 'namespace'].include?(key) }
|
10
|
+
filtered_hash['counters'] = JSON.parse(filtered_hash['counters'], symbolize_names: true) if filtered_hash['counters']
|
11
|
+
filtered_hash.symbolize_keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def write!(minter)
|
15
|
+
# namespace and template are the same, now update the other attributes
|
16
|
+
instance.update_attributes!(
|
17
|
+
seq: minter.seq,
|
18
|
+
counters: JSON.generate(minter.counters),
|
19
|
+
rand: Marshal.dump(minter.instance_variable_get(:@rand))
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
7
23
|
protected
|
8
24
|
|
9
25
|
# Uses pessimistic lock to ensure the record fetched is the same one updated.
|
@@ -19,21 +35,20 @@ module ActiveFedora
|
|
19
35
|
def next_id
|
20
36
|
id = nil
|
21
37
|
MinterState.transaction do
|
22
|
-
state =
|
23
|
-
|
24
|
-
template: ActiveFedora::Noid.config.template,
|
25
|
-
).first!
|
26
|
-
minter = ::Noid::Minter.new(state.noid_options)
|
38
|
+
state = read
|
39
|
+
minter = ::Noid::Minter.new(state)
|
27
40
|
id = minter.mint
|
28
|
-
|
29
|
-
state.seq = minter.seq
|
30
|
-
state.counters = JSON.generate(minter.counters)
|
31
|
-
state.random = Marshal.dump(minter.instance_variable_get(:@rand))
|
32
|
-
state.save!
|
41
|
+
write!(minter)
|
33
42
|
end # transaction
|
34
43
|
id
|
35
44
|
end
|
36
45
|
|
46
|
+
def instance
|
47
|
+
MinterState.lock.find_by(
|
48
|
+
namespace: ActiveFedora::Noid.config.namespace,
|
49
|
+
template: ActiveFedora::Noid.config.template,
|
50
|
+
)
|
51
|
+
end
|
37
52
|
end # class Db
|
38
53
|
end
|
39
54
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'noid'
|
2
|
+
|
3
|
+
module ActiveFedora
|
4
|
+
module Noid
|
5
|
+
module Minter
|
6
|
+
class File < Base
|
7
|
+
attr_reader :statefile
|
8
|
+
|
9
|
+
def initialize(template = default_template, statefile = default_statefile)
|
10
|
+
@statefile = statefile
|
11
|
+
super(template)
|
12
|
+
end
|
13
|
+
|
14
|
+
def default_statefile
|
15
|
+
ActiveFedora::Noid.config.statefile
|
16
|
+
end
|
17
|
+
|
18
|
+
def read
|
19
|
+
with_file do |f|
|
20
|
+
state_for(f)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def write!(minter)
|
25
|
+
with_file do |f|
|
26
|
+
# Wipe prior contents so the new state can be written from the beginning of the file
|
27
|
+
f.truncate(0)
|
28
|
+
f.write(Marshal.dump(minter.dump))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def with_file
|
35
|
+
::File.open(statefile, 'a+b', 0644) do |f|
|
36
|
+
f.flock(::File::LOCK_EX)
|
37
|
+
# Files opened in append mode seek to end of file
|
38
|
+
f.rewind
|
39
|
+
yield f
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def state_for(io_object)
|
44
|
+
Marshal.load(io_object.read)
|
45
|
+
rescue TypeError, ArgumentError
|
46
|
+
{ template: template }
|
47
|
+
end
|
48
|
+
|
49
|
+
def next_id
|
50
|
+
state = read
|
51
|
+
state[:template] &&= state[:template].to_s
|
52
|
+
minter = ::Noid::Minter.new(state) # minter w/in the minter, lives only for an instant
|
53
|
+
id = minter.mint
|
54
|
+
write!(minter)
|
55
|
+
id
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/tasks/noid_tasks.rake
CHANGED
@@ -4,25 +4,51 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
namespace :active_fedora do
|
6
6
|
namespace :noid do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
namespace :migrate do
|
8
|
+
desc 'Migrate minter state file from YAML to Marshal'
|
9
|
+
task :yaml_to_marshal do
|
10
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
11
|
+
raise "File not found: #{statefile}\nAborting" unless File.exist?(statefile)
|
12
|
+
puts "Migrating #{statefile} from YAML to Marshal serialization..."
|
13
|
+
File.open(statefile, 'a+b', 0644) do |f|
|
14
|
+
f.flock(File::LOCK_EX)
|
15
|
+
f.rewind
|
16
|
+
begin
|
17
|
+
yaml_state = YAML.load(f)
|
18
|
+
rescue Psych::SyntaxError
|
19
|
+
raise "File not valid YAML: #{statefile}\nAborting."
|
20
|
+
end
|
21
|
+
minter = Noid::Minter.new(yaml_state)
|
22
|
+
f.truncate(0)
|
23
|
+
new_state = Marshal.dump(minter.dump)
|
24
|
+
f.write(new_state)
|
19
25
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
26
|
+
puts "Done!"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Migrate minter state from file to database'
|
30
|
+
task file_to_database: :environment do
|
31
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
32
|
+
raise "File not found: #{statefile}\nAborting" unless File.exist?(statefile)
|
33
|
+
puts "Migrating #{statefile} to database..."
|
34
|
+
state = ActiveFedora::Noid::Minter::File.new.read
|
35
|
+
minter = Noid::Minter.new(state)
|
36
|
+
new_state = ActiveFedora::Noid::Minter::Db.new
|
37
|
+
new_state.write!(minter)
|
38
|
+
puts "Done!"
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Migrate minter state from database to file'
|
42
|
+
task database_to_file: :environment do
|
43
|
+
statefile = ENV.fetch('AFNOID_STATEFILE', ActiveFedora::Noid.config.statefile)
|
44
|
+
raise "File already exists (delete it first if it's not valuable): #{statefile}\nAborting" if File.exist?(statefile)
|
45
|
+
puts "Migrating minter state from database to #{statefile}..."
|
46
|
+
state = ActiveFedora::Noid::Minter::Db.new.read
|
47
|
+
minter = Noid::Minter.new(state)
|
48
|
+
new_state = ActiveFedora::Noid::Minter::File.new
|
49
|
+
new_state.write!(minter)
|
50
|
+
puts "Done!"
|
24
51
|
end
|
25
|
-
puts "Done!"
|
26
52
|
end
|
27
53
|
end
|
28
54
|
end
|
@@ -37,22 +37,4 @@ describe MinterState, type: :model do
|
|
37
37
|
expect(described_class.group(:namespace).count).to eq('default' => 1, 'foobar' => 1)
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
41
|
-
describe '#noid_options' do
|
42
|
-
it 'returns nil without template (new object not persisted)' do
|
43
|
-
expect(state.noid_options).to be_nil
|
44
|
-
end
|
45
|
-
it 'returns correct hash when populated' do
|
46
|
-
state.template = '.reeddddk'
|
47
|
-
state.seq = 1
|
48
|
-
expect(state.noid_options).to match a_hash_including(
|
49
|
-
:template => '.reeddddk',
|
50
|
-
:seq => 1
|
51
|
-
)
|
52
|
-
expect(first.noid_options).to match a_hash_including(
|
53
|
-
:template => '.reeddeeddk',
|
54
|
-
:seq => 0
|
55
|
-
)
|
56
|
-
end
|
57
|
-
end
|
58
40
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
shared_examples 'a minter' do
|
2
|
+
describe '#mint' do
|
3
|
+
subject { minter.mint }
|
4
|
+
let(:other) { described_class.new('.reedddk') }
|
5
|
+
|
6
|
+
it { is_expected.not_to be_empty }
|
7
|
+
|
8
|
+
it 'does not mint the same ID twice in a row' do
|
9
|
+
expect(subject).not_to eq described_class.new.mint
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'is valid' do
|
13
|
+
expect(minter.valid?(subject)).to be true
|
14
|
+
expect(described_class.new.valid?(subject)).to be true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is invalid under a different template' do
|
18
|
+
expect(described_class.new('.reedddk').valid?(subject)).to be false
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'is invalid under a different template' do
|
22
|
+
expect(other).not_to be_valid(minter.mint)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'conflicts' do
|
27
|
+
let(:existing_pid) { 'ef12ef12f' }
|
28
|
+
let(:unique_pid) { 'bb22bb22b' }
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
expect(subject).to receive(:next_id).and_return(existing_pid, unique_pid)
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the pid already exists in Fedora' do
|
35
|
+
before do
|
36
|
+
expect(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
|
37
|
+
end
|
38
|
+
it 'skips the existing pid' do
|
39
|
+
expect(subject.mint).to eq unique_pid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the pid already existed in Fedora and now is gone' do
|
44
|
+
let(:gone_pid) { existing_pid }
|
45
|
+
|
46
|
+
before do
|
47
|
+
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'skips the deleted pid' do
|
51
|
+
expect(subject.mint).to eq unique_pid
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/spec/unit/config_spec.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
describe ActiveFedora::Noid::Config do
|
2
|
+
subject { described_class.new }
|
3
|
+
|
2
4
|
it { is_expected.to respond_to(:template) }
|
3
5
|
it { is_expected.to respond_to(:statefile) }
|
4
6
|
it { is_expected.to respond_to(:namespace) }
|
7
|
+
it { is_expected.to respond_to(:minter_class) }
|
5
8
|
it { is_expected.to respond_to(:translate_id_to_uri) }
|
6
9
|
it { is_expected.to respond_to(:translate_uri_to_id) }
|
7
10
|
|
@@ -23,6 +26,22 @@ describe ActiveFedora::Noid::Config do
|
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
29
|
+
describe '#minter_class' do
|
30
|
+
let(:default) { ActiveFedora::Noid::Minter::Db }
|
31
|
+
|
32
|
+
it 'has a default' do
|
33
|
+
expect(subject.minter_class).to eq default
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when overridden' do
|
37
|
+
before { subject.minter_class = different_minter }
|
38
|
+
let(:different_minter) { ActiveFedora::Noid::Minter::File }
|
39
|
+
it 'uses the different minter' do
|
40
|
+
expect(subject.minter_class).to eq different_minter
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
26
45
|
describe '#translate_uri_to_id' do
|
27
46
|
let(:config) { described_class.new }
|
28
47
|
let(:translator) { config.translate_uri_to_id }
|
@@ -38,10 +57,10 @@ describe ActiveFedora::Noid::Config do
|
|
38
57
|
|
39
58
|
context "with a hash code uri" do
|
40
59
|
let(:uri) { "http://localhost:8983/fedora/rest/test/hh/63/vz/22/hh63vz22q#g123" }
|
41
|
-
|
60
|
+
it { is_expected.to eq 'hh63vz22q#g123' }
|
42
61
|
end
|
43
62
|
|
44
|
-
|
63
|
+
context 'with a short custom template' do
|
45
64
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
|
46
65
|
let(:custom_template) { '.reeee' }
|
47
66
|
before { config.template = custom_template }
|
@@ -50,7 +69,7 @@ describe ActiveFedora::Noid::Config do
|
|
50
69
|
it { is_expected.to eq 'abcd/members' }
|
51
70
|
end
|
52
71
|
|
53
|
-
|
72
|
+
context 'with an even shorter custom template' do
|
54
73
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
|
55
74
|
let(:custom_template) { '.reee' }
|
56
75
|
before { config.template = custom_template }
|
@@ -59,7 +78,7 @@ describe ActiveFedora::Noid::Config do
|
|
59
78
|
it { is_expected.to eq 'abc/members' }
|
60
79
|
end
|
61
80
|
|
62
|
-
|
81
|
+
context 'with a long custom template' do
|
63
82
|
let(:uri) { "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
|
64
83
|
let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
|
65
84
|
before { config.template = custom_template }
|
@@ -67,6 +86,48 @@ describe ActiveFedora::Noid::Config do
|
|
67
86
|
|
68
87
|
it { is_expected.to eq 'abcdefghijklmnopqrstuvwxyz/members' }
|
69
88
|
end
|
89
|
+
end
|
70
90
|
|
91
|
+
describe '#translate_id_to_uri' do
|
92
|
+
let(:config) { described_class.new }
|
93
|
+
let(:translator) { config.translate_id_to_uri }
|
94
|
+
let(:id) { "hh63vz2/members" }
|
95
|
+
let(:ActiveFedora) { double(ActiveFedora) }
|
96
|
+
subject { translator.call(id) }
|
97
|
+
before do
|
98
|
+
allow(ActiveFedora).to receive_message_chain("fedora.host") { "http://localhost:8983" }
|
99
|
+
allow(ActiveFedora).to receive_message_chain("fedora.base_path") { "/fedora/rest/test" }
|
100
|
+
end
|
101
|
+
|
102
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2/members" }
|
103
|
+
|
104
|
+
context "with a hash code id" do
|
105
|
+
let(:id) { 'hh63vz2#g123' }
|
106
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/hh/63/vz/2/hh63vz2#g123" }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with a short custom template' do
|
110
|
+
let(:id) { "abcd/members" }
|
111
|
+
let(:custom_template) { '.reeee' }
|
112
|
+
before { config.template = custom_template }
|
113
|
+
subject { translator.call(id) }
|
114
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/abcd/members" }
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with an even shorter custom template' do
|
118
|
+
let(:id) { 'abc/members' }
|
119
|
+
let(:custom_template) { '.reee' }
|
120
|
+
before { config.template = custom_template }
|
121
|
+
subject { translator.call(id) }
|
122
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/c/abc/members" }
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'with a long custom template' do
|
126
|
+
let(:id) { "abcdefghijklmnopqrstuvwxyz/members" }
|
127
|
+
let(:custom_template) { '.reeeeeeeeeeeeeeeeeeeeeeeeee' }
|
128
|
+
before { config.template = custom_template }
|
129
|
+
subject { translator.call(id) }
|
130
|
+
it { is_expected.to eq "http://localhost:8983/fedora/rest/test/ab/cd/ef/gh/abcdefghijklmnopqrstuvwxyz/members" }
|
131
|
+
end
|
71
132
|
end
|
72
133
|
end
|
data/spec/unit/db_minter_spec.rb
CHANGED
@@ -2,7 +2,7 @@ include MinterStateHelper
|
|
2
2
|
|
3
3
|
describe ActiveFedora::Noid::Minter::Db do
|
4
4
|
before(:each) { reset_minter_state_table }
|
5
|
-
after(
|
5
|
+
after(:all) { reset_minter_state_table }
|
6
6
|
|
7
7
|
before :each do
|
8
8
|
# default novel mintings
|
@@ -10,19 +10,22 @@ describe ActiveFedora::Noid::Minter::Db do
|
|
10
10
|
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
11
11
|
end
|
12
12
|
|
13
|
-
let(:minter) { described_class.new }
|
14
13
|
let(:other) { described_class.new('.reedddk') }
|
15
14
|
|
15
|
+
it_behaves_like 'a minter' do
|
16
|
+
let(:minter) { described_class.new }
|
17
|
+
end
|
18
|
+
|
16
19
|
describe '#initialize' do
|
17
20
|
it 'raises on bad templates' do
|
18
21
|
expect{ described_class.new('reeddeeddk') }.to raise_error(Noid::TemplateError)
|
19
22
|
expect{ described_class.new('') }.to raise_error(Noid::TemplateError)
|
20
23
|
end
|
21
24
|
it 'returns object w/ default template' do
|
22
|
-
expect(
|
23
|
-
expect(
|
24
|
-
expect(
|
25
|
-
expect(
|
25
|
+
expect(subject).to be_instance_of described_class
|
26
|
+
expect(subject).to be_a Noid::Minter
|
27
|
+
expect(subject.template).to be_instance_of Noid::Template
|
28
|
+
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
26
29
|
end
|
27
30
|
it 'accepts valid template arg' do
|
28
31
|
expect(other).to be_instance_of described_class
|
@@ -32,45 +35,29 @@ describe ActiveFedora::Noid::Minter::Db do
|
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
|
-
describe '#
|
36
|
-
|
37
|
-
|
38
|
-
it 'does not mint the same ID twice in a row' do
|
39
|
-
expect(subject).not_to eq described_class.new.mint
|
38
|
+
describe '#read' do
|
39
|
+
it 'returns a hash' do
|
40
|
+
expect(subject.read).to be_a(Hash)
|
40
41
|
end
|
41
|
-
it '
|
42
|
-
expect(
|
43
|
-
expect(described_class.new.valid?(subject)).to be true
|
42
|
+
it 'has the expected namespace' do
|
43
|
+
expect(subject.read[:namespace]).to eq ActiveFedora::Noid.config.namespace
|
44
44
|
end
|
45
|
-
it '
|
46
|
-
expect(
|
45
|
+
it 'has the expected template' do
|
46
|
+
expect(subject.read[:template]).to eq ActiveFedora::Noid.config.template
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
let(:
|
52
|
-
let(:
|
53
|
-
before
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
it 'skips the existing pid' do
|
62
|
-
expect(minter.mint).to eq unique_pid
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'when the pid already existed in Fedora and now is gone' do
|
67
|
-
let(:gone_pid) { existing_pid }
|
68
|
-
before do
|
69
|
-
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
70
|
-
end
|
71
|
-
it 'skips the deleted pid' do
|
72
|
-
expect(minter.mint).to eq unique_pid
|
73
|
-
end
|
50
|
+
describe '#write!' do
|
51
|
+
let(:starting_state) { subject.read }
|
52
|
+
let(:minter) { Noid::Minter.new(starting_state) }
|
53
|
+
before { minter.mint }
|
54
|
+
it 'changes the state of the minter' do
|
55
|
+
expect { subject.write!(minter) }.to change { subject.read[:seq] }
|
56
|
+
.from(starting_state[:seq]).to(minter.seq)
|
57
|
+
.and change { subject.read[:counters] }
|
58
|
+
.from(starting_state[:counters]).to(minter.counters)
|
59
|
+
.and change { subject.read[:rand] }
|
60
|
+
.from(starting_state[:rand]).to(Marshal.dump(minter.instance_variable_get(:@rand)))
|
74
61
|
end
|
75
62
|
end
|
76
63
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe ActiveFedora::Noid::Minter::File do
|
2
|
+
before :each do
|
3
|
+
# default novel mintings
|
4
|
+
allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
|
5
|
+
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
6
|
+
end
|
7
|
+
|
8
|
+
it { is_expected.to respond_to(:mint) }
|
9
|
+
|
10
|
+
it 'has a default statefile' do
|
11
|
+
expect(subject.statefile).to eq ActiveFedora::Noid.config.statefile
|
12
|
+
end
|
13
|
+
it 'has a default template' do
|
14
|
+
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
15
|
+
end
|
16
|
+
|
17
|
+
it_behaves_like 'a minter' do
|
18
|
+
let(:minter) { described_class.new }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#initialize' do
|
22
|
+
let(:template) { '.rededk' }
|
23
|
+
let(:statefile) { '/tmp/foobar' }
|
24
|
+
|
25
|
+
subject { described_class.new(template, statefile) }
|
26
|
+
|
27
|
+
it 'respects the custom template' do
|
28
|
+
expect(subject.template.to_s).to eq template
|
29
|
+
end
|
30
|
+
it 'respects the custom statefile' do
|
31
|
+
expect(subject.statefile).to eq statefile
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#read' do
|
36
|
+
it 'returns a hash' do
|
37
|
+
expect(subject.read).to be_a(Hash)
|
38
|
+
end
|
39
|
+
it 'has the expected template' do
|
40
|
+
expect(subject.read[:template]).to eq ActiveFedora::Noid.config.template
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#write!' do
|
45
|
+
let(:starting_state) { subject.read }
|
46
|
+
let(:minter) { Noid::Minter.new(starting_state) }
|
47
|
+
before { minter.mint }
|
48
|
+
it 'changes the state of the minter' do
|
49
|
+
expect { subject.write!(minter) }.to change { subject.read[:seq] }
|
50
|
+
.from(starting_state[:seq]).to(minter.seq)
|
51
|
+
.and change { subject.read[:rand] }
|
52
|
+
.from(starting_state[:rand]).to(Marshal.dump(minter.instance_variable_get(:@rand)))
|
53
|
+
.and change { subject.read[:counters] }
|
54
|
+
.to(minter.counters)
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/unit/noid_spec.rb
CHANGED
@@ -13,5 +13,9 @@ describe ActiveFedora::Noid do
|
|
13
13
|
subject { ActiveFedora::Noid.treeify(id) }
|
14
14
|
let(:id) { 'abc123def45' }
|
15
15
|
it { is_expected.to eq 'ab/c1/23/de/abc123def45' }
|
16
|
+
context 'with a seven-digit identifier' do
|
17
|
+
let(:id) { 'abc123z' }
|
18
|
+
it { is_expected.to eq 'ab/c1/23/z/abc123z' }
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
data/spec/unit/service_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe ActiveFedora::Noid::Service do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
it 'has a default minter' do
|
8
|
-
expect(subject.minter).to be_instance_of ActiveFedora::Noid::
|
8
|
+
expect(subject.minter).to be_instance_of ActiveFedora::Noid::Minter::Db
|
9
9
|
end
|
10
10
|
|
11
11
|
context 'with a custom minter' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_fedora-noid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael J. Giarlo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active-fedora
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 4.2.
|
53
|
+
version: 4.2.7.1
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '6'
|
@@ -60,7 +60,7 @@ dependencies:
|
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 4.2.
|
63
|
+
version: 4.2.7.1
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '6'
|
@@ -84,14 +84,14 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
87
|
+
version: '11.0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
94
|
+
version: '11.0'
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
96
|
name: rspec
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +126,14 @@ dependencies:
|
|
126
126
|
requirements:
|
127
127
|
- - "~>"
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version: '0
|
129
|
+
version: '1.0'
|
130
130
|
type: :development
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version: '0
|
136
|
+
version: '1.0'
|
137
137
|
description: Noid identifier services for ActiveFedora-based applications.
|
138
138
|
email:
|
139
139
|
- leftwing@alumni.rutgers.edu
|
@@ -152,13 +152,15 @@ files:
|
|
152
152
|
- active_fedora-noid.gemspec
|
153
153
|
- app/models/minter_state.rb
|
154
154
|
- db/migrate/20160610010003_create_minter_states.rb
|
155
|
+
- db/migrate/20161021203429_rename_minter_state_random_to_rand.rb
|
155
156
|
- lib/active_fedora/noid.rb
|
156
157
|
- lib/active_fedora/noid/config.rb
|
157
158
|
- lib/active_fedora/noid/engine.rb
|
159
|
+
- lib/active_fedora/noid/minter.rb
|
158
160
|
- lib/active_fedora/noid/minter/base.rb
|
159
161
|
- lib/active_fedora/noid/minter/db.rb
|
162
|
+
- lib/active_fedora/noid/minter/file.rb
|
160
163
|
- lib/active_fedora/noid/service.rb
|
161
|
-
- lib/active_fedora/noid/synchronized_minter.rb
|
162
164
|
- lib/active_fedora/noid/version.rb
|
163
165
|
- lib/generators/active_fedora/noid/install_generator.rb
|
164
166
|
- lib/generators/active_fedora/noid/seed_generator.rb
|
@@ -166,12 +168,13 @@ files:
|
|
166
168
|
- spec/models/minter_state_spec.rb
|
167
169
|
- spec/spec_helper.rb
|
168
170
|
- spec/support/minterstate_table.rb
|
171
|
+
- spec/support/shared_examples/minter.rb
|
169
172
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
170
173
|
- spec/unit/config_spec.rb
|
171
174
|
- spec/unit/db_minter_spec.rb
|
175
|
+
- spec/unit/file_minter_spec.rb
|
172
176
|
- spec/unit/noid_spec.rb
|
173
177
|
- spec/unit/service_spec.rb
|
174
|
-
- spec/unit/synchronized_minter_spec.rb
|
175
178
|
homepage: https://github.com/projecthydra-labs/active_fedora-noid
|
176
179
|
licenses:
|
177
180
|
- Apache2
|
@@ -200,9 +203,10 @@ test_files:
|
|
200
203
|
- spec/models/minter_state_spec.rb
|
201
204
|
- spec/spec_helper.rb
|
202
205
|
- spec/support/minterstate_table.rb
|
206
|
+
- spec/support/shared_examples/minter.rb
|
203
207
|
- spec/test_app_templates/lib/generators/test_app_generator.rb
|
204
208
|
- spec/unit/config_spec.rb
|
205
209
|
- spec/unit/db_minter_spec.rb
|
210
|
+
- spec/unit/file_minter_spec.rb
|
206
211
|
- spec/unit/noid_spec.rb
|
207
212
|
- spec/unit/service_spec.rb
|
208
|
-
- spec/unit/synchronized_minter_spec.rb
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'noid'
|
2
|
-
|
3
|
-
module ActiveFedora
|
4
|
-
module Noid
|
5
|
-
class SynchronizedMinter < Minter::Base
|
6
|
-
attr_reader :statefile
|
7
|
-
|
8
|
-
def initialize(template = default_template, statefile = default_statefile)
|
9
|
-
super(template)
|
10
|
-
@statefile = statefile
|
11
|
-
end
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def default_statefile
|
16
|
-
ActiveFedora::Noid.config.statefile
|
17
|
-
end
|
18
|
-
|
19
|
-
def state_for(io_object)
|
20
|
-
Marshal.load(io_object.read)
|
21
|
-
rescue TypeError, ArgumentError
|
22
|
-
{ template: template }
|
23
|
-
end
|
24
|
-
|
25
|
-
def next_id
|
26
|
-
id = nil
|
27
|
-
::File.open(statefile, 'a+b', 0644) do |f|
|
28
|
-
f.flock(::File::LOCK_EX)
|
29
|
-
# Files opened in append mode seek to end of file
|
30
|
-
f.rewind
|
31
|
-
state = state_for(f)
|
32
|
-
state[:template] &&= state[:template].to_s
|
33
|
-
minter = ::Noid::Minter.new(state) # minter w/in the minter, lives only for an instant
|
34
|
-
id = minter.mint
|
35
|
-
|
36
|
-
# Wipe prior contents so the new state can be written from the beginning of the file
|
37
|
-
f.truncate(0)
|
38
|
-
new_state = Marshal.dump(minter.dump)
|
39
|
-
f.write(new_state)
|
40
|
-
end
|
41
|
-
id
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
describe ActiveFedora::Noid::SynchronizedMinter do
|
2
|
-
before :each do
|
3
|
-
# default novel mintings
|
4
|
-
allow(ActiveFedora::Base).to receive(:exists?).and_return(false)
|
5
|
-
allow(ActiveFedora::Base).to receive(:gone?).and_return(false)
|
6
|
-
end
|
7
|
-
|
8
|
-
let(:minter) { described_class.new }
|
9
|
-
|
10
|
-
it { is_expected.to respond_to(:mint) }
|
11
|
-
it 'has a default statefile' do
|
12
|
-
expect(subject.statefile).to eq ActiveFedora::Noid.config.statefile
|
13
|
-
end
|
14
|
-
it 'has a default template' do
|
15
|
-
expect(subject.template.to_s).to eq ActiveFedora::Noid.config.template
|
16
|
-
end
|
17
|
-
|
18
|
-
describe '#initialize' do
|
19
|
-
let(:template) { '.rededk' }
|
20
|
-
let(:statefile) { '/tmp/foobar' }
|
21
|
-
|
22
|
-
subject { described_class.new(template, statefile) }
|
23
|
-
|
24
|
-
it 'respects the custom template' do
|
25
|
-
expect(subject.template.to_s).to eq template
|
26
|
-
end
|
27
|
-
it 'respects the custom statefile' do
|
28
|
-
expect(subject.statefile).to eq statefile
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe '#mint' do
|
33
|
-
subject { minter.mint }
|
34
|
-
it { is_expected.not_to be_empty }
|
35
|
-
it 'does not mint the same ID twice in a row' do
|
36
|
-
expect(subject).not_to eq described_class.new.mint
|
37
|
-
end
|
38
|
-
it 'is valid' do
|
39
|
-
expect(minter.valid?(subject)).to be true
|
40
|
-
expect(described_class.new.valid?(subject)).to be true
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'conflicts' do
|
45
|
-
let(:unique_pid) { 'bb22bb22b' }
|
46
|
-
let(:existing_pid) { 'ef12ef12f' }
|
47
|
-
before :each do
|
48
|
-
expect(minter).to receive(:next_id).and_return(existing_pid, unique_pid)
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'when the pid already exists in Fedora' do
|
52
|
-
before do
|
53
|
-
expect(ActiveFedora::Base).to receive(:exists?).with(existing_pid).and_return(true)
|
54
|
-
end
|
55
|
-
it 'skips the existing pid' do
|
56
|
-
expect(minter.mint).to eq unique_pid
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'when the pid already existed in Fedora and now is gone' do
|
61
|
-
let(:gone_pid) { existing_pid }
|
62
|
-
before do
|
63
|
-
expect(ActiveFedora::Base).to receive(:gone?).with(gone_pid).and_return(true)
|
64
|
-
end
|
65
|
-
it 'skips the deleted pid' do
|
66
|
-
expect(minter.mint).to eq unique_pid
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|