remote_files 1.2.2 → 1.3.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.
- data/lib/remote_files/configuration.rb +123 -0
- data/lib/remote_files/file.rb +19 -20
- data/lib/remote_files/fog_store.rb +2 -2
- data/lib/remote_files/memory_store.rb +4 -2
- data/lib/remote_files/version.rb +1 -1
- data/lib/remote_files.rb +18 -82
- data/test/configuration_test.rb +178 -0
- data/test/remote_files_test.rb +0 -173
- data/test/resque_job_test.rb +2 -1
- data/test/test_helper.rb +3 -2
- metadata +11 -8
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'remote_files/fog_store'
|
2
|
+
|
3
|
+
module RemoteFiles
|
4
|
+
class Configuration
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name, config = {})
|
8
|
+
@name = name
|
9
|
+
@stores = []
|
10
|
+
@stores_map = {}
|
11
|
+
from_hash(config)
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
15
|
+
@stores.clear
|
16
|
+
@stores_map.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_hash(hash)
|
20
|
+
hash.each do |store_identifier, config|
|
21
|
+
#symbolize_keys!
|
22
|
+
cfg = {}
|
23
|
+
config.each { |name, value| cfg[name.to_sym] = config[name] }
|
24
|
+
config = cfg
|
25
|
+
|
26
|
+
#camelize
|
27
|
+
type = config[:type].gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } + 'Store'
|
28
|
+
|
29
|
+
klass = RemoteFiles.const_get(type) rescue nil
|
30
|
+
unless klass
|
31
|
+
require "remote_files/#{config[:type]}_store"
|
32
|
+
klass = RemoteFiles.const_get(type)
|
33
|
+
end
|
34
|
+
|
35
|
+
config.delete(:type)
|
36
|
+
|
37
|
+
add_store(store_identifier.to_sym, :class => klass, :primary => !!config.delete(:primary)) do |store|
|
38
|
+
config.each do |name, value|
|
39
|
+
store[name] = value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_store(store_identifier, options = {}, &block)
|
48
|
+
store = (options[:class] || FogStore).new(store_identifier)
|
49
|
+
block.call(store) if block_given?
|
50
|
+
|
51
|
+
if options[:primary]
|
52
|
+
@stores.unshift(store)
|
53
|
+
else
|
54
|
+
@stores << store
|
55
|
+
end
|
56
|
+
|
57
|
+
@stores_map[store_identifier] = store
|
58
|
+
end
|
59
|
+
|
60
|
+
def stores
|
61
|
+
raise "You need to configure add stores to the #{name} RemoteFiles configuration" if @stores.empty?
|
62
|
+
@stores
|
63
|
+
end
|
64
|
+
|
65
|
+
def lookup_store(store_identifier)
|
66
|
+
@stores_map[store_identifier]
|
67
|
+
end
|
68
|
+
|
69
|
+
def primary_store
|
70
|
+
stores.first
|
71
|
+
end
|
72
|
+
|
73
|
+
def store_once!(file)
|
74
|
+
return file.stored_in.first if file.stored?
|
75
|
+
|
76
|
+
exception = nil
|
77
|
+
|
78
|
+
stores.each do |store|
|
79
|
+
begin
|
80
|
+
stored = store.store!(file)
|
81
|
+
file.stored_in << store.identifier
|
82
|
+
break
|
83
|
+
rescue ::RemoteFiles::Error => e
|
84
|
+
exception = e
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
raise exception unless file.stored?
|
89
|
+
|
90
|
+
file.stored_in.first
|
91
|
+
end
|
92
|
+
|
93
|
+
def store!(file)
|
94
|
+
store_once!(file) unless file.stored?
|
95
|
+
|
96
|
+
RemoteFiles.synchronize_stores(file) unless file.stored_everywhere?
|
97
|
+
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete!(file)
|
102
|
+
file.stored_in.each do |store_identifier|
|
103
|
+
store = lookup_store(store_identifier)
|
104
|
+
store.delete!(file.identifier)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def synchronize!(file)
|
109
|
+
file.missing_stores.each do |store_identifier|
|
110
|
+
store = lookup_store(store_identifier)
|
111
|
+
store.store!(file)
|
112
|
+
file.stored_in << store.identifier
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def file_from_url(url)
|
117
|
+
stores.each do |store|
|
118
|
+
file = store.file_from_url(url)
|
119
|
+
return file if file
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/remote_files/file.rb
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
module RemoteFiles
|
2
2
|
class File
|
3
|
-
attr_reader :content, :content_type, :identifier, :stored_in
|
3
|
+
attr_reader :content, :content_type, :identifier, :stored_in, :configuration
|
4
4
|
|
5
5
|
def initialize(identifier, options = {})
|
6
|
-
@identifier
|
7
|
-
@stored_in
|
8
|
-
@content
|
9
|
-
@content_type
|
10
|
-
@
|
6
|
+
@identifier = identifier
|
7
|
+
@stored_in = options[:stored_in] || []
|
8
|
+
@content = options.delete(:content)
|
9
|
+
@content_type = options[:content_type]
|
10
|
+
@configuration = RemoteFiles::CONFIGURATIONS[options[:configuration] || :default]
|
11
|
+
@options = options
|
11
12
|
end
|
12
13
|
|
13
14
|
def self.from_url(url)
|
14
|
-
RemoteFiles.
|
15
|
-
file = store.file_from_url(url)
|
16
|
-
return file if file
|
17
|
-
end
|
15
|
+
RemoteFiles.default_configuration.file_from_url(url)
|
18
16
|
end
|
19
17
|
|
20
18
|
def options
|
21
19
|
@options.merge(
|
22
|
-
:identifier
|
23
|
-
:stored_in
|
24
|
-
:content_type
|
20
|
+
:identifier => identifier,
|
21
|
+
:stored_in => stored_in,
|
22
|
+
:content_type => content_type,
|
23
|
+
:configuration => configuration.name
|
25
24
|
)
|
26
25
|
end
|
27
26
|
|
@@ -34,17 +33,17 @@ module RemoteFiles
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def missing_stores
|
37
|
-
|
36
|
+
configuration.stores.map(&:identifier) - @stored_in
|
38
37
|
end
|
39
38
|
|
40
39
|
def url(store_identifier = nil)
|
41
|
-
store = store_identifier ?
|
40
|
+
store = store_identifier ? configuration.lookup_store(store_identifier) : configuration.primary_store
|
42
41
|
return nil unless store
|
43
42
|
store.url(identifier)
|
44
43
|
end
|
45
44
|
|
46
45
|
def current_url
|
47
|
-
prioritized_stores =
|
46
|
+
prioritized_stores = configuration.stores.map(&:identifier) & @stored_in
|
48
47
|
|
49
48
|
return nil if prioritized_stores.empty?
|
50
49
|
|
@@ -52,19 +51,19 @@ module RemoteFiles
|
|
52
51
|
end
|
53
52
|
|
54
53
|
def store!
|
55
|
-
|
54
|
+
configuration.store!(self)
|
56
55
|
end
|
57
56
|
|
58
57
|
def store_once!
|
59
|
-
|
58
|
+
configuration.store_once!(self)
|
60
59
|
end
|
61
60
|
|
62
61
|
def synchronize!
|
63
|
-
|
62
|
+
configuration.synchronize!(self)
|
64
63
|
end
|
65
64
|
|
66
65
|
def delete!
|
67
|
-
|
66
|
+
configuration.delete!(self)
|
68
67
|
end
|
69
68
|
|
70
69
|
def delete
|
@@ -4,14 +4,14 @@ require 'fog'
|
|
4
4
|
module RemoteFiles
|
5
5
|
class FogStore < AbstractStore
|
6
6
|
def store!(file)
|
7
|
-
|
7
|
+
success = directory.files.create(
|
8
8
|
:body => file.content,
|
9
9
|
:content_type => file.content_type,
|
10
10
|
:key => file.identifier,
|
11
11
|
:public => options[:public]
|
12
12
|
)
|
13
13
|
|
14
|
-
raise RemoteFiles::Error unless
|
14
|
+
raise RemoteFiles::Error unless success
|
15
15
|
|
16
16
|
true
|
17
17
|
rescue Fog::Errors::Error, Excon::Errors::Error
|
@@ -12,8 +12,10 @@ module RemoteFiles
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.clear!
|
15
|
-
RemoteFiles.
|
16
|
-
|
15
|
+
RemoteFiles::CONFIGURATIONS.values.each do |config|
|
16
|
+
config.stores.each do |store|
|
17
|
+
store.clear! if store.is_a?(RemoteFiles::MemoryStore)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
data/lib/remote_files/version.rb
CHANGED
data/lib/remote_files.rb
CHANGED
@@ -1,107 +1,43 @@
|
|
1
1
|
require 'remote_files/version'
|
2
|
-
require 'remote_files/
|
2
|
+
require 'remote_files/configuration'
|
3
3
|
require 'remote_files/file'
|
4
4
|
|
5
5
|
module RemoteFiles
|
6
6
|
class Error < StandardError; end
|
7
7
|
class NotFoundError < Error; end
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
CONFIGURATIONS = Hash.new do |configs, name|
|
10
|
+
name = name.to_sym
|
11
|
+
configs[name] = Configuration.new(name)
|
12
|
+
end
|
11
13
|
|
12
|
-
def self.
|
13
|
-
|
14
|
-
|
14
|
+
def self.default_configuration
|
15
|
+
CONFIGURATIONS[:default]
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def self.configure(name, hash = {})
|
19
|
+
if name.is_a?(Hash)
|
20
|
+
hash = name
|
21
|
+
name = :default
|
20
22
|
end
|
21
23
|
|
22
|
-
|
24
|
+
CONFIGURATIONS[name].from_hash(hash)
|
23
25
|
end
|
24
26
|
|
25
|
-
def self.
|
26
|
-
|
27
|
-
#symbolize_keys!
|
28
|
-
cfg = {}
|
29
|
-
config.each { |name, value| cfg[name.to_sym] = config[name] }
|
30
|
-
config = cfg
|
31
|
-
|
32
|
-
#camelize
|
33
|
-
type = config[:type].gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } + 'Store'
|
34
|
-
|
35
|
-
klass = RemoteFiles.const_get(type) rescue nil
|
36
|
-
unless klass
|
37
|
-
require "remote_files/#{config[:type]}_store"
|
38
|
-
klass = RemoteFiles.const_get(type)
|
39
|
-
end
|
40
|
-
|
41
|
-
config.delete(:type)
|
42
|
-
|
43
|
-
add_store(store_identifier.to_sym, :class => klass, :primary => !!config.delete(:primary)) do |store|
|
44
|
-
config.each do |name, value|
|
45
|
-
store[name] = value
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
27
|
+
def self.add_store(store_identifier, options = {}, &block)
|
28
|
+
default_configuration.add_store(store_identifier, options, &block)
|
49
29
|
end
|
50
30
|
|
51
31
|
def self.stores
|
52
|
-
|
53
|
-
STORES
|
32
|
+
default_configuration.stores
|
54
33
|
end
|
55
34
|
|
56
35
|
def self.lookup_store(store_identifier)
|
57
|
-
|
36
|
+
default_configuration.lookup_store(store_identifier)
|
58
37
|
end
|
59
38
|
|
60
39
|
def self.primary_store
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.store_once!(file)
|
65
|
-
return file.stored_in.first if file.stored?
|
66
|
-
|
67
|
-
exception = nil
|
68
|
-
|
69
|
-
stores.each do |store|
|
70
|
-
begin
|
71
|
-
stored = store.store!(file)
|
72
|
-
file.stored_in << store.identifier
|
73
|
-
break
|
74
|
-
rescue ::RemoteFiles::Error => e
|
75
|
-
exception = e
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
raise exception unless file.stored?
|
80
|
-
|
81
|
-
file.stored_in.first
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.store!(file)
|
85
|
-
store_once!(file) unless file.stored?
|
86
|
-
|
87
|
-
synchronize_stores(file) unless file.stored_everywhere?
|
88
|
-
|
89
|
-
true
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.delete!(file)
|
93
|
-
file.stored_in.each do |store_identifier|
|
94
|
-
store = lookup_store(store_identifier)
|
95
|
-
store.delete!(file.identifier)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.synchronize!(file)
|
100
|
-
file.missing_stores.each do |store_identifier|
|
101
|
-
store = lookup_store(store_identifier)
|
102
|
-
store.store!(file)
|
103
|
-
file.stored_in << store.identifier
|
104
|
-
end
|
40
|
+
default_configuration.primary_store
|
105
41
|
end
|
106
42
|
|
107
43
|
def self.synchronize_stores(file = nil, &block)
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
require 'remote_files/mock_store'
|
3
|
+
|
4
|
+
describe RemoteFiles::Configuration do
|
5
|
+
before do
|
6
|
+
@configuration = RemoteFiles.configure(:test)
|
7
|
+
@file = RemoteFiles::File.new('file', :configuration => :test, :content => 'content', :content_type => 'text/plain')
|
8
|
+
@mock_store1 = @configuration.add_store(:mock1, :class => RemoteFiles::MockStore)
|
9
|
+
@mock_store2 = @configuration.add_store(:mock2, :class => RemoteFiles::MockStore)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '::add_store' do
|
13
|
+
describe 'when adding a non-primary store' do
|
14
|
+
before { @non_primary_store = @configuration.add_store(:primary) }
|
15
|
+
|
16
|
+
it 'should add it to the tail of the list of stores' do
|
17
|
+
@configuration.stores.must_equal([@mock_store1, @mock_store2, @non_primary_store])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'when adding a promary store' do
|
22
|
+
before { @primary_store = @configuration.add_store(:primary, :primary => true) }
|
23
|
+
|
24
|
+
it 'should add it to the head of the list of stores' do
|
25
|
+
@configuration.stores.must_equal([@primary_store, @mock_store1, @mock_store2])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '::primary_store' do
|
31
|
+
before do
|
32
|
+
@primary_store1 = @configuration.add_store(:primary1, :primary => true)
|
33
|
+
@primary_store2 = @configuration.add_store(:primary2, :primary => true)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return the head of the list of stores' do
|
37
|
+
@configuration.primary_store.must_equal(@primary_store2)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '::lookup_store' do
|
42
|
+
before do
|
43
|
+
@primary_store = @configuration.add_store(:primary, :primary => true)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should find the store my identifier' do
|
47
|
+
@configuration.lookup_store(:mock1).must_equal(@mock_store1)
|
48
|
+
@configuration.lookup_store(:mock2).must_equal(@mock_store2)
|
49
|
+
@configuration.lookup_store(:primary).must_equal(@primary_store)
|
50
|
+
@configuration.lookup_store(:unknown).must_be_nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '::store_once!' do
|
55
|
+
|
56
|
+
describe 'when the first store succeeds' do
|
57
|
+
before { @configuration.store_once!(@file) }
|
58
|
+
|
59
|
+
it 'should only store the file in the first store' do
|
60
|
+
@mock_store1.data['file'].must_equal(:content => 'content', :content_type => 'text/plain')
|
61
|
+
@mock_store2.data['file'].must_be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'when the first store fails' do
|
66
|
+
before do
|
67
|
+
@mock_store1.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
68
|
+
@configuration.store_once!(@file)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should only store the file in the second store' do
|
72
|
+
@mock_store1.data['file'].must_be_nil
|
73
|
+
@mock_store2.data['file'].must_equal(:content => 'content', :content_type => 'text/plain')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'when alls stores fail' do
|
78
|
+
before do
|
79
|
+
@mock_store1.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
80
|
+
@mock_store2.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should raise a RemoteFiles::Error' do
|
84
|
+
proc { @configuration.store_once!(@file) }.must_raise(RemoteFiles::Error)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '::store!' do
|
90
|
+
describe 'when the file is already stored in some stores' do
|
91
|
+
before { @file.stored_in.replace([@mock_store1.identifier]) }
|
92
|
+
|
93
|
+
it 'should not store the file' do
|
94
|
+
@configuration.expects(:store_once!).never
|
95
|
+
@configuration.store!(@file)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should synchronize the stores' do
|
99
|
+
RemoteFiles.expects(:synchronize_stores).with(@file)
|
100
|
+
@configuration.store!(@file)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'when the file is stored in all stores' do
|
105
|
+
before { @file.stored_in.replace([@mock_store1.identifier, @mock_store2.identifier]) }
|
106
|
+
|
107
|
+
it 'should not store the file' do
|
108
|
+
@configuration.expects(:store_once!).never
|
109
|
+
@configuration.store!(@file)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should not synchronize the stores' do
|
113
|
+
RemoteFiles.expects(:synchronize_stores).never
|
114
|
+
@configuration.store!(@file)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'when the file is not stored anywhere' do
|
120
|
+
before { @file.stored_in.replace([]) }
|
121
|
+
|
122
|
+
it 'should store the file once' do
|
123
|
+
@file.configuration.expects(:store_once!).with(@file)
|
124
|
+
@configuration.store!(@file)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should synchronize the stores' do
|
128
|
+
RemoteFiles.expects(:synchronize_stores).with(@file)
|
129
|
+
@configuration.store!(@file)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '::delete!' do
|
135
|
+
it 'should delete the file from all the stores' do
|
136
|
+
@file.stored_in.replace([:mock1, :mock2])
|
137
|
+
@mock_store1.expects(:delete!).with(@file.identifier)
|
138
|
+
@mock_store2.expects(:delete!).with(@file.identifier)
|
139
|
+
@configuration.delete!(@file)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '::synchronize!' do
|
144
|
+
describe 'when the file is not stored anywhere' do
|
145
|
+
before { @file.stored_in.replace([]) }
|
146
|
+
|
147
|
+
it 'should store the file on all stores' do
|
148
|
+
@mock_store1.expects(:store!).returns(true)
|
149
|
+
@mock_store2.expects(:store!).returns(true)
|
150
|
+
|
151
|
+
@configuration.synchronize!(@file)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe 'when the file is stored in some stores' do
|
156
|
+
before { @file.stored_in.replace([@mock_store1.identifier]) }
|
157
|
+
|
158
|
+
it 'should store the file in the remaining stores' do
|
159
|
+
@mock_store1.expects(:store!).never
|
160
|
+
@mock_store2.expects(:store!).with(@file).returns(true)
|
161
|
+
|
162
|
+
@configuration.synchronize!(@file)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe 'when the file is stored everywhere' do
|
167
|
+
before { @file.stored_in.replace([@mock_store1.identifier, @mock_store2.identifier]) }
|
168
|
+
|
169
|
+
it 'should not do anything' do
|
170
|
+
@mock_store1.expects(:store!).never
|
171
|
+
@mock_store2.expects(:store!).never
|
172
|
+
|
173
|
+
@configuration.synchronize!(@file)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
data/test/remote_files_test.rb
CHANGED
@@ -1,90 +1,6 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
|
-
require 'remote_files/mock_store'
|
3
2
|
|
4
3
|
describe RemoteFiles do
|
5
|
-
before do
|
6
|
-
@file = RemoteFiles::File.new('file', :content => 'content', :content_type => 'text/plain')
|
7
|
-
@mock_store1 = RemoteFiles.add_store(:mock1, :class => RemoteFiles::MockStore)
|
8
|
-
@mock_store2 = RemoteFiles.add_store(:mock2, :class => RemoteFiles::MockStore)
|
9
|
-
end
|
10
|
-
|
11
|
-
describe '::add_store' do
|
12
|
-
describe 'when adding a non-primary store' do
|
13
|
-
before { @non_primary_store = RemoteFiles.add_store(:primary) }
|
14
|
-
|
15
|
-
it 'should add it to the tail of the list of stores' do
|
16
|
-
RemoteFiles.stores.must_equal([@mock_store1, @mock_store2, @non_primary_store])
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe 'when adding a promary store' do
|
21
|
-
before { @primary_store = RemoteFiles.add_store(:primary, :primary => true) }
|
22
|
-
|
23
|
-
it 'should add it to the head of the list of stores' do
|
24
|
-
RemoteFiles.stores.must_equal([@primary_store, @mock_store1, @mock_store2])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe '::primary_store' do
|
30
|
-
before do
|
31
|
-
@primary_store1 = RemoteFiles.add_store(:primary1, :primary => true)
|
32
|
-
@primary_store2 = RemoteFiles.add_store(:primary2, :primary => true)
|
33
|
-
end
|
34
|
-
|
35
|
-
it 'should return the head of the list of stores' do
|
36
|
-
RemoteFiles.primary_store.must_equal(@primary_store2)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe '::lookup_store' do
|
41
|
-
before do
|
42
|
-
@primary_store = RemoteFiles.add_store(:primary, :primary => true)
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should find the store my identifier' do
|
46
|
-
RemoteFiles.lookup_store(:mock1).must_equal(@mock_store1)
|
47
|
-
RemoteFiles.lookup_store(:mock2).must_equal(@mock_store2)
|
48
|
-
RemoteFiles.lookup_store(:primary).must_equal(@primary_store)
|
49
|
-
RemoteFiles.lookup_store(:unknown).must_be_nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe '::store_once!' do
|
54
|
-
|
55
|
-
describe 'when the first store succeeds' do
|
56
|
-
before { RemoteFiles.store_once!(@file) }
|
57
|
-
|
58
|
-
it 'should only store the file in the first store' do
|
59
|
-
@mock_store1.data['file'].must_equal(:content => 'content', :content_type => 'text/plain')
|
60
|
-
@mock_store2.data['file'].must_be_nil
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe 'when the first store fails' do
|
65
|
-
before do
|
66
|
-
@mock_store1.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
67
|
-
RemoteFiles.store_once!(@file)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'should only store the file in the second store' do
|
71
|
-
@mock_store1.data['file'].must_be_nil
|
72
|
-
@mock_store2.data['file'].must_equal(:content => 'content', :content_type => 'text/plain')
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe 'when alls stores fail' do
|
77
|
-
before do
|
78
|
-
@mock_store1.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
79
|
-
@mock_store2.expects(:store!).with(@file).raises(RemoteFiles::Error)
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'should raise a RemoteFiles::Error' do
|
83
|
-
proc { RemoteFiles.store_once!(@file) }.must_raise(RemoteFiles::Error)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
4
|
describe '::synchronize_stores' do
|
89
5
|
before do
|
90
6
|
@files = []
|
@@ -101,93 +17,4 @@ describe RemoteFiles do
|
|
101
17
|
end
|
102
18
|
end
|
103
19
|
|
104
|
-
describe '::store!' do
|
105
|
-
describe 'when the file is already stored in some stores' do
|
106
|
-
before { @file.stored_in.replace([@mock_store1.identifier]) }
|
107
|
-
|
108
|
-
it 'should not store the file' do
|
109
|
-
RemoteFiles.expects(:store_once!).never
|
110
|
-
RemoteFiles.store!(@file)
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'should synchronize the stores' do
|
114
|
-
RemoteFiles.expects(:synchronize_stores).with(@file)
|
115
|
-
RemoteFiles.store!(@file)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
describe 'when the file is stored in all stores' do
|
120
|
-
before { @file.stored_in.replace([@mock_store1.identifier, @mock_store2.identifier]) }
|
121
|
-
|
122
|
-
it 'should not store the file' do
|
123
|
-
RemoteFiles.expects(:store_once!).never
|
124
|
-
RemoteFiles.store!(@file)
|
125
|
-
end
|
126
|
-
|
127
|
-
it 'should not synchronize the stores' do
|
128
|
-
RemoteFiles.expects(:synchronize_stores).never
|
129
|
-
RemoteFiles.store!(@file)
|
130
|
-
end
|
131
|
-
|
132
|
-
end
|
133
|
-
|
134
|
-
describe 'when the file is not stored anywhere' do
|
135
|
-
before { @file.stored_in.replace([]) }
|
136
|
-
|
137
|
-
it 'should store the file once' do
|
138
|
-
RemoteFiles.expects(:store_once!).with(@file)
|
139
|
-
RemoteFiles.store!(@file)
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'should synchronize the stores' do
|
143
|
-
RemoteFiles.expects(:synchronize_stores).with(@file)
|
144
|
-
RemoteFiles.store!(@file)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
describe '::delete!' do
|
150
|
-
it 'should delete the file from all the stores' do
|
151
|
-
@file.stored_in.replace([:mock1, :mock2])
|
152
|
-
@mock_store1.expects(:delete!).with(@file.identifier)
|
153
|
-
@mock_store2.expects(:delete!).with(@file.identifier)
|
154
|
-
RemoteFiles.delete!(@file)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
describe '::synchronize!' do
|
159
|
-
describe 'when the file is not stored anywhere' do
|
160
|
-
before { @file.stored_in.replace([]) }
|
161
|
-
|
162
|
-
it 'should store the file on all stores' do
|
163
|
-
@mock_store1.expects(:store!).returns(true)
|
164
|
-
@mock_store2.expects(:store!).returns(true)
|
165
|
-
|
166
|
-
RemoteFiles.synchronize!(@file)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
describe 'when the file is stored in some stores' do
|
171
|
-
before { @file.stored_in.replace([@mock_store1.identifier]) }
|
172
|
-
|
173
|
-
it 'should store the file in the remaining stores' do
|
174
|
-
@mock_store1.expects(:store!).never
|
175
|
-
@mock_store2.expects(:store!).with(@file).returns(true)
|
176
|
-
|
177
|
-
RemoteFiles.synchronize!(@file)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
describe 'when the file is stored everywhere' do
|
182
|
-
before { @file.stored_in.replace([@mock_store1.identifier, @mock_store2.identifier]) }
|
183
|
-
|
184
|
-
it 'should not do anything' do
|
185
|
-
@mock_store1.expects(:store!).never
|
186
|
-
@mock_store2.expects(:store!).never
|
187
|
-
|
188
|
-
RemoteFiles.synchronize!(@file)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
20
|
end
|
data/test/resque_job_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -15,8 +15,9 @@ MiniTest::Spec.class_eval do
|
|
15
15
|
before do
|
16
16
|
Fog::Mock.reset
|
17
17
|
|
18
|
-
RemoteFiles::
|
19
|
-
|
18
|
+
RemoteFiles::CONFIGURATIONS.values.each do |conf|
|
19
|
+
conf.clear
|
20
|
+
end
|
20
21
|
|
21
22
|
$syncs = []
|
22
23
|
RemoteFiles.synchronize_stores do |file|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: remote_files
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -48,17 +48,17 @@ dependencies:
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 3.4.0
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 3.4.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: debugger
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,6 +116,7 @@ extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
117
117
|
files:
|
118
118
|
- lib/remote_files/abstract_store.rb
|
119
|
+
- lib/remote_files/configuration.rb
|
119
120
|
- lib/remote_files/file.rb
|
120
121
|
- lib/remote_files/file_store.rb
|
121
122
|
- lib/remote_files/fog_store.rb
|
@@ -124,6 +125,7 @@ files:
|
|
124
125
|
- lib/remote_files/resque_job.rb
|
125
126
|
- lib/remote_files/version.rb
|
126
127
|
- lib/remote_files.rb
|
128
|
+
- test/configuration_test.rb
|
127
129
|
- test/file_store_test.rb
|
128
130
|
- test/file_test.rb
|
129
131
|
- test/fog_store_test.rb
|
@@ -146,7 +148,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
148
|
version: '0'
|
147
149
|
segments:
|
148
150
|
- 0
|
149
|
-
hash:
|
151
|
+
hash: -1536087519966001179
|
150
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
153
|
none: false
|
152
154
|
requirements:
|
@@ -155,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
157
|
version: '0'
|
156
158
|
segments:
|
157
159
|
- 0
|
158
|
-
hash:
|
160
|
+
hash: -1536087519966001179
|
159
161
|
requirements: []
|
160
162
|
rubyforge_project:
|
161
163
|
rubygems_version: 1.8.24
|
@@ -165,6 +167,7 @@ summary: The purpose of the library is to implement a simple interface for uploa
|
|
165
167
|
files to multiple backends and to keep the backends in sync, so that your app will
|
166
168
|
keep working when one backend is down.
|
167
169
|
test_files:
|
170
|
+
- test/configuration_test.rb
|
168
171
|
- test/file_store_test.rb
|
169
172
|
- test/file_test.rb
|
170
173
|
- test/fog_store_test.rb
|