asset_cloud 2.7.1 → 2.7.2
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/.github/workflows/ci.yml +20 -5
- data/.github/workflows/cla.yml +22 -0
- data/.rubocop.yml +3 -1
- data/Gemfile +5 -3
- data/History.md +4 -0
- data/Rakefile +18 -16
- data/asset_cloud.gemspec +19 -18
- data/dev.yml +1 -1
- data/lib/asset_cloud/asset.rb +17 -13
- data/lib/asset_cloud/asset_extension.rb +27 -15
- data/lib/asset_cloud/base.rb +77 -72
- data/lib/asset_cloud/bucket.rb +5 -2
- data/lib/asset_cloud/buckets/active_record_bucket.rb +16 -14
- data/lib/asset_cloud/buckets/blackhole_bucket.rb +2 -0
- data/lib/asset_cloud/buckets/bucket_chain.rb +38 -31
- data/lib/asset_cloud/buckets/file_system_bucket.rb +14 -15
- data/lib/asset_cloud/buckets/gcs_bucket.rb +6 -8
- data/lib/asset_cloud/buckets/invalid_bucket.rb +9 -6
- data/lib/asset_cloud/buckets/memory_bucket.rb +7 -4
- data/lib/asset_cloud/buckets/s3_bucket.rb +11 -8
- data/lib/asset_cloud/buckets/versioned_memory_bucket.rb +4 -2
- data/lib/asset_cloud/callbacks.rb +7 -3
- data/lib/asset_cloud/free_key_locator.rb +6 -6
- data/lib/asset_cloud/metadata.rb +11 -7
- data/lib/asset_cloud/validations.rb +9 -5
- data/lib/asset_cloud.rb +23 -21
- data/spec/active_record_bucket_spec.rb +27 -26
- data/spec/asset_cloud/metadata_spec.rb +4 -2
- data/spec/asset_extension_spec.rb +17 -16
- data/spec/asset_spec.rb +27 -21
- data/spec/base_spec.rb +93 -92
- data/spec/blackhole_bucket_spec.rb +12 -11
- data/spec/bucket_chain_spec.rb +61 -56
- data/spec/bucket_spec.rb +6 -5
- data/spec/callbacks_spec.rb +41 -39
- data/spec/file_system_spec.rb +25 -24
- data/spec/find_free_key_spec.rb +16 -17
- data/spec/gcs_bucket_remote_spec.rb +23 -22
- data/spec/gcs_bucket_spec.rb +48 -60
- data/spec/memory_bucket_spec.rb +12 -11
- data/spec/mock_s3_interface.rb +17 -6
- data/spec/remote_s3_bucket_spec.rb +31 -28
- data/spec/s3_bucket_spec.rb +19 -17
- data/spec/spec_helper.rb +8 -7
- data/spec/validations_spec.rb +13 -12
- data/spec/versioned_memory_bucket_spec.rb +11 -10
- metadata +9 -32
- data/.github/probots.yml +0 -2
- data/.rubocop_todo.yml +0 -326
data/spec/base_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
class SpecialAsset < AssetCloud::Asset
|
5
6
|
end
|
@@ -16,182 +17,182 @@ end
|
|
16
17
|
class BasicCloud < AssetCloud::Base
|
17
18
|
bucket :special, AssetCloud::MemoryBucket, asset_class: SpecialAsset
|
18
19
|
bucket :conditional, AssetCloud::MemoryBucket, asset_class: proc { |key|
|
19
|
-
LiquidAsset if key.ends_with?(
|
20
|
+
LiquidAsset if key.ends_with?(".liquid")
|
20
21
|
}
|
21
22
|
bucket :broken, BrokenBucket, asset_class: AssetCloud::Asset
|
22
23
|
end
|
23
24
|
|
24
25
|
describe BasicCloud do
|
25
|
-
directory = File.dirname(__FILE__) +
|
26
|
+
directory = File.dirname(__FILE__) + "/files"
|
26
27
|
|
27
28
|
before do
|
28
|
-
@fs = BasicCloud.new(directory,
|
29
|
+
@fs = BasicCloud.new(directory, "http://assets/files")
|
29
30
|
end
|
30
31
|
|
31
32
|
it "should raise invalid bucket if none is given" do
|
32
|
-
expect(@fs[
|
33
|
+
expect(@fs["image.jpg"].exist?).to(eq(false))
|
33
34
|
end
|
34
35
|
|
35
36
|
it "should be backed by a file system bucket" do
|
36
|
-
expect(@fs[
|
37
|
+
expect(@fs["products/key.txt"].exist?).to(eq(true))
|
37
38
|
end
|
38
39
|
|
39
40
|
it "should raise when listing non existing buckets" do
|
40
|
-
expect(@fs.ls(
|
41
|
+
expect(@fs.ls("products")).to(eq([AssetCloud::Asset.new(@fs, "products/key.txt")]))
|
41
42
|
end
|
42
43
|
|
43
44
|
it "should allow you to create new assets" do
|
44
|
-
obj = @fs.build(
|
45
|
+
obj = @fs.build("new_file.test")
|
45
46
|
expect(obj).to(be_an_instance_of(AssetCloud::Asset))
|
46
47
|
expect(obj.cloud).to(be_an_instance_of(BasicCloud))
|
47
48
|
end
|
48
49
|
|
49
50
|
it "should raise error when using with minus relative or absolute paths" do
|
50
|
-
expect { @fs[
|
51
|
-
expect { @fs[
|
52
|
-
expect { @fs[
|
53
|
-
expect { @fs[
|
51
|
+
expect { @fs["../test"] }.to(raise_error(AssetCloud::IllegalPath))
|
52
|
+
expect { @fs["/test"] }.to(raise_error(AssetCloud::IllegalPath))
|
53
|
+
expect { @fs[".../test"] }.to(raise_error(AssetCloud::IllegalPath))
|
54
|
+
expect { @fs["./test"] }.to(raise_error(AssetCloud::IllegalPath))
|
54
55
|
end
|
55
56
|
|
56
57
|
it "should raise error when filename has trailing period" do
|
57
|
-
expect { @fs[
|
58
|
-
expect { @fs[
|
59
|
-
expect { @fs[
|
60
|
-
expect { @fs[
|
61
|
-
expect { @fs[
|
58
|
+
expect { @fs["test."] }.to(raise_error(AssetCloud::IllegalPath))
|
59
|
+
expect { @fs["/test/testfile."] }.to(raise_error(AssetCloud::IllegalPath))
|
60
|
+
expect { @fs["test/directory/."] }.to(raise_error(AssetCloud::IllegalPath))
|
61
|
+
expect { @fs["/test/testfile ."] }.to(raise_error(AssetCloud::IllegalPath))
|
62
|
+
expect { @fs["test/directory /."] }.to(raise_error(AssetCloud::IllegalPath))
|
62
63
|
end
|
63
64
|
|
64
65
|
it "should raise error when filename ends with space" do
|
65
|
-
expect { @fs[
|
66
|
-
expect { @fs[
|
67
|
-
expect { @fs[
|
68
|
-
expect { @fs[
|
69
|
-
expect { @fs[
|
70
|
-
expect { @fs[
|
66
|
+
expect { @fs["test "] }.to(raise_error(AssetCloud::IllegalPath))
|
67
|
+
expect { @fs["/test/testfile "] }.to(raise_error(AssetCloud::IllegalPath))
|
68
|
+
expect { @fs["test/directory/ "] }.to(raise_error(AssetCloud::IllegalPath))
|
69
|
+
expect { @fs["test. "] }.to(raise_error(AssetCloud::IllegalPath))
|
70
|
+
expect { @fs["/test/testfile. "] }.to(raise_error(AssetCloud::IllegalPath))
|
71
|
+
expect { @fs["test/directory/. "] }.to(raise_error(AssetCloud::IllegalPath))
|
71
72
|
end
|
72
73
|
|
73
74
|
it "should raise error when filename ends with slash" do
|
74
|
-
expect { @fs[
|
75
|
-
expect { @fs[
|
76
|
-
expect { @fs[
|
77
|
-
expect { @fs[
|
78
|
-
expect { @fs[
|
75
|
+
expect { @fs["test/"] }.to(raise_error(AssetCloud::IllegalPath))
|
76
|
+
expect { @fs["test/directory/"] }.to(raise_error(AssetCloud::IllegalPath))
|
77
|
+
expect { @fs["test /"] }.to(raise_error(AssetCloud::IllegalPath))
|
78
|
+
expect { @fs["/test/testfile /"] }.to(raise_error(AssetCloud::IllegalPath))
|
79
|
+
expect { @fs["test/directory//"] }.to(raise_error(AssetCloud::IllegalPath))
|
79
80
|
end
|
80
81
|
|
81
82
|
it "should raise error when using with minus relative even after another directory" do
|
82
|
-
expect { @fs[
|
83
|
-
expect { @fs[
|
84
|
-
expect { @fs[
|
83
|
+
expect { @fs["test/../test"] }.to(raise_error(AssetCloud::IllegalPath))
|
84
|
+
expect { @fs["test/../../test"] }.to(raise_error(AssetCloud::IllegalPath))
|
85
|
+
expect { @fs["test/../../../test"] }.to(raise_error(AssetCloud::IllegalPath))
|
85
86
|
end
|
86
87
|
|
87
88
|
it "should raise an error when using names with combinations of '.' and ' '" do
|
88
|
-
expect { @fs[
|
89
|
-
expect { @fs[
|
90
|
-
expect { @fs[
|
89
|
+
expect { @fs["test. . . .. ... .. . "] }.to(raise_error(AssetCloud::IllegalPath))
|
90
|
+
expect { @fs["test. ."] }.to(raise_error(AssetCloud::IllegalPath))
|
91
|
+
expect { @fs["test. .test2"] }.to(raise_error(AssetCloud::IllegalPath))
|
91
92
|
end
|
92
93
|
|
93
94
|
it "should allow filenames with repeating dots" do
|
94
|
-
@fs[
|
95
|
-
@fs[
|
96
|
-
@fs[
|
95
|
+
@fs["test..jpg"]
|
96
|
+
@fs["assets/T.T..jpg"]
|
97
|
+
@fs["test/assets/1234123412341234_obj_description..14...58......v8...._2134123412341234.jpg"]
|
97
98
|
end
|
98
99
|
|
99
100
|
it "should allow filenames with repeating underscores" do
|
100
|
-
@fs[
|
101
|
-
@fs[
|
102
|
-
@fs[
|
101
|
+
@fs["test__jpg"]
|
102
|
+
@fs["assets/T__T..jpg"]
|
103
|
+
@fs["test/assets/1234123412341234_obj_description..14...58......v8...__2134123412341234.jpg"]
|
103
104
|
end
|
104
105
|
|
105
106
|
it "should allow filenames with various bracket arragements" do
|
106
|
-
@fs[
|
107
|
-
@fs[
|
108
|
-
@fs[
|
107
|
+
@fs["test[1].jpg"]
|
108
|
+
@fs["test[1]"]
|
109
|
+
@fs["[test].jpg"]
|
109
110
|
end
|
110
111
|
|
111
112
|
it "should not raise an error when using directory names with spaces" do
|
112
|
-
@fs[
|
113
|
+
@fs["files/ass ets/.DS_Store"]
|
113
114
|
end
|
114
115
|
|
115
116
|
it "should not raise_error when using unusual but valid filenames" do
|
116
|
-
@fs[
|
117
|
-
@fs[
|
118
|
-
@fs[
|
119
|
-
@fs[
|
120
|
-
@fs[
|
121
|
-
@fs[
|
122
|
-
@fs[
|
117
|
+
@fs[".DS_Store"]
|
118
|
+
@fs["photograph.g"]
|
119
|
+
@fs["_testfilename"]
|
120
|
+
@fs["assets/.DS_Store"]
|
121
|
+
@fs["assets/photograph.g"]
|
122
|
+
@fs["a/_testfilename"]
|
123
|
+
@fs["a"]
|
123
124
|
end
|
124
125
|
|
125
126
|
it "should allow sensible relative filenames" do
|
126
|
-
@fs[
|
127
|
-
@fs[
|
128
|
-
@fs[
|
129
|
-
@fs[
|
130
|
-
@fs[
|
127
|
+
@fs["assets/rails_logo.gif"]
|
128
|
+
@fs["assets/rails_logo"]
|
129
|
+
@fs["assets/rails-2.gif"]
|
130
|
+
@fs["assets/223434.gif"]
|
131
|
+
@fs["files/1.JPG"]
|
131
132
|
end
|
132
133
|
|
133
134
|
it "should compute complete urls to assets" do
|
134
|
-
expect(@fs.url_for(
|
135
|
+
expect(@fs.url_for("products/[key] with spaces.txt?foo=1&bar=2")).to(eq("http://assets/files/products/[key]%20with%20spaces.txt?foo=1&bar=2"))
|
135
136
|
end
|
136
137
|
|
137
138
|
describe "#find" do
|
138
139
|
it "should return the appropriate asset when one exists" do
|
139
|
-
asset = @fs.find(
|
140
|
-
expect(asset.key).to(eq(
|
141
|
-
expect(asset.value).to(eq(
|
140
|
+
asset = @fs.find("products/key.txt")
|
141
|
+
expect(asset.key).to(eq("products/key.txt"))
|
142
|
+
expect(asset.value).to(eq("value"))
|
142
143
|
end
|
143
144
|
it "should raise AssetNotFoundError when the asset doesn't exist" do
|
144
|
-
expect { @fs.find(
|
145
|
+
expect { @fs.find("products/not-there.txt") }.to(raise_error(AssetCloud::AssetNotFoundError))
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
148
149
|
describe "#[]" do
|
149
150
|
it "should return the appropriate asset when one exists" do
|
150
|
-
asset = @fs[
|
151
|
-
expect(asset.key).to(eq(
|
152
|
-
expect(asset.value).to(eq(
|
151
|
+
asset = @fs["products/key.txt"]
|
152
|
+
expect(asset.key).to(eq("products/key.txt"))
|
153
|
+
expect(asset.value).to(eq("value"))
|
153
154
|
end
|
154
155
|
it "should not raise any errors when the asset doesn't exist" do
|
155
|
-
expect { @fs[
|
156
|
+
expect { @fs["products/not-there.txt"] }.not_to(raise_error)
|
156
157
|
end
|
157
158
|
end
|
158
159
|
|
159
160
|
describe "#move" do
|
160
161
|
it "should return move a resource" do
|
161
|
-
asset = @fs[
|
162
|
-
expect(asset.key).to(eq(
|
163
|
-
expect(asset.value).to(eq(
|
164
|
-
@fs.move(
|
165
|
-
new_asset = @fs[
|
166
|
-
expect(new_asset.key).to(eq(
|
167
|
-
expect(new_asset.value).to(eq(
|
168
|
-
expect { @fs[
|
169
|
-
@fs.move(
|
162
|
+
asset = @fs["products/key.txt"]
|
163
|
+
expect(asset.key).to(eq("products/key.txt"))
|
164
|
+
expect(asset.value).to(eq("value"))
|
165
|
+
@fs.move("products/key.txt", "products/key2.txt")
|
166
|
+
new_asset = @fs["products/key2.txt"]
|
167
|
+
expect(new_asset.key).to(eq("products/key2.txt"))
|
168
|
+
expect(new_asset.value).to(eq("value"))
|
169
|
+
expect { @fs["products/key.txt"].value }.to(raise_error(AssetCloud::AssetNotFoundError))
|
170
|
+
@fs.move("products/key2.txt", "products/key.txt")
|
170
171
|
end
|
171
172
|
end
|
172
173
|
|
173
174
|
describe "#[]=" do
|
174
175
|
it "should write through the Asset object (and thus run any callbacks on the asset)" do
|
175
176
|
special_asset = double(:special_asset)
|
176
|
-
expect(special_asset).to(receive(:value=).with(
|
177
|
+
expect(special_asset).to(receive(:value=).with("fancy fancy!"))
|
177
178
|
expect(special_asset).to(receive(:store))
|
178
179
|
expect(SpecialAsset).to(receive(:at).and_return(special_asset))
|
179
|
-
@fs[
|
180
|
+
@fs["special/fancy.txt"] = "fancy fancy!"
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
183
184
|
describe "#bucket" do
|
184
185
|
it "should allow specifying a class to use for assets in this bucket" do
|
185
|
-
expect(@fs[
|
186
|
-
expect(@fs[
|
186
|
+
expect(@fs["assets/rails_logo.gif"]).to(be_instance_of(AssetCloud::Asset))
|
187
|
+
expect(@fs["special/fancy.txt"]).to(be_instance_of(SpecialAsset))
|
187
188
|
|
188
|
-
expect(@fs.build(
|
189
|
-
expect(@fs.build(
|
189
|
+
expect(@fs.build("assets/foo")).to(be_instance_of(AssetCloud::Asset))
|
190
|
+
expect(@fs.build("special/foo")).to(be_instance_of(SpecialAsset))
|
190
191
|
end
|
191
192
|
|
192
193
|
it "should allow specifying a proc that determines the class to use, using the default bucket when returning nil" do
|
193
|
-
expect(@fs.build(
|
194
|
-
expect(@fs.build(
|
194
|
+
expect(@fs.build("conditional/default.js")).to(be_instance_of(AssetCloud::Asset))
|
195
|
+
expect(@fs.build("conditional/better.liquid")).to(be_instance_of(LiquidAsset))
|
195
196
|
end
|
196
197
|
|
197
198
|
it "should raise " do
|
@@ -202,30 +203,30 @@ describe BasicCloud do
|
|
202
203
|
describe "write!" do
|
203
204
|
it "should write through the Asset object (and thus run any callbacks on the asset)" do
|
204
205
|
special_asset = double(:special_asset)
|
205
|
-
expect(special_asset).to(receive(:value=).with(
|
206
|
+
expect(special_asset).to(receive(:value=).with("fancy fancy!"))
|
206
207
|
expect(special_asset).to(receive(:store!))
|
207
208
|
expect(SpecialAsset).to(receive(:at).and_return(special_asset))
|
208
|
-
@fs.write!(
|
209
|
+
@fs.write!("special/fancy.txt", "fancy fancy!")
|
209
210
|
end
|
210
211
|
|
211
212
|
it "should raise AssetNotSaved when write fails" do
|
212
|
-
expect { @fs.write!(
|
213
|
+
expect { @fs.write!("broken/file.txt", "n/a") }.to(raise_error(AssetCloud::AssetNotSaved))
|
213
214
|
end
|
214
215
|
end
|
215
216
|
|
216
217
|
describe "MATCH_BUCKET" do
|
217
218
|
it "should match following stuff " do
|
218
|
-
|
219
|
-
expect(Regexp.last_match(1)).to(eq(
|
219
|
+
"products/key.txt" =~ AssetCloud::Base::MATCH_BUCKET
|
220
|
+
expect(Regexp.last_match(1)).to(eq("products"))
|
220
221
|
|
221
|
-
|
222
|
-
expect(Regexp.last_match(1)).to(eq(
|
222
|
+
"products/subpath/key.txt" =~ AssetCloud::Base::MATCH_BUCKET
|
223
|
+
expect(Regexp.last_match(1)).to(eq("products"))
|
223
224
|
|
224
|
-
|
225
|
+
"key.txt" =~ AssetCloud::Base::MATCH_BUCKET
|
225
226
|
expect(Regexp.last_match(1)).to(eq(nil))
|
226
227
|
|
227
|
-
|
228
|
-
expect(Regexp.last_match(1)).to(eq(
|
228
|
+
"products" =~ AssetCloud::Base::MATCH_BUCKET
|
229
|
+
expect(Regexp.last_match(1)).to(eq("products"))
|
229
230
|
end
|
230
231
|
end
|
231
232
|
end
|
@@ -1,42 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
class BlackholeCloud < AssetCloud::Base
|
5
6
|
bucket AssetCloud::BlackholeBucket
|
6
7
|
end
|
7
8
|
|
8
9
|
describe BlackholeCloud do
|
9
|
-
directory = File.dirname(__FILE__) +
|
10
|
+
directory = File.dirname(__FILE__) + "/files"
|
10
11
|
|
11
12
|
before do
|
12
|
-
@fs = BlackholeCloud.new(directory,
|
13
|
+
@fs = BlackholeCloud.new(directory, "http://assets/files")
|
13
14
|
end
|
14
15
|
|
15
16
|
it "should allow access to files using the [] operator" do
|
16
|
-
@fs[
|
17
|
+
@fs["tmp/image.jpg"]
|
17
18
|
end
|
18
19
|
|
19
20
|
it "should return nil for non existent files" do
|
20
|
-
expect(@fs[
|
21
|
+
expect(@fs["tmp/image.jpg"].exist?).to(eq(false))
|
21
22
|
end
|
22
23
|
|
23
24
|
it "should still return nil, even if you wrote something there" do
|
24
|
-
@fs[
|
25
|
-
expect(@fs[
|
25
|
+
@fs["tmp/image.jpg"] = "test"
|
26
|
+
expect(@fs["tmp/image.jpg"].exist?).to(eq(false))
|
26
27
|
end
|
27
28
|
|
28
29
|
describe "when using a sub path" do
|
29
30
|
it "should allow access to files using the [] operator" do
|
30
|
-
@fs[
|
31
|
+
@fs["tmp/image.jpg"]
|
31
32
|
end
|
32
33
|
|
33
34
|
it "should return nil for non existent files" do
|
34
|
-
expect(@fs[
|
35
|
+
expect(@fs["tmp/image.jpg"].exist?).to(eq(false))
|
35
36
|
end
|
36
37
|
|
37
38
|
it "should still return nil, even if you wrote something there" do
|
38
|
-
@fs[
|
39
|
-
expect(@fs[
|
39
|
+
@fs["tmp/image.jpg"] = "test"
|
40
|
+
expect(@fs["tmp/image.jpg"].exist?).to(eq(false))
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
data/spec/bucket_chain_spec.rb
CHANGED
@@ -1,93 +1,98 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'spec_helper'
|
3
2
|
|
4
|
-
|
5
|
-
bucket :stuff, AssetCloud::BucketChain.chain(AssetCloud::MemoryBucket,
|
6
|
-
AssetCloud::MemoryBucket,
|
7
|
-
AssetCloud::FileSystemBucket)
|
3
|
+
require "spec_helper"
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
class ChainedCloud < AssetCloud::Base
|
6
|
+
bucket :stuff, AssetCloud::BucketChain.chain(
|
7
|
+
AssetCloud::MemoryBucket,
|
8
|
+
AssetCloud::MemoryBucket,
|
9
|
+
AssetCloud::FileSystemBucket,
|
10
|
+
)
|
11
|
+
|
12
|
+
bucket :versioned_stuff, AssetCloud::BucketChain.chain(
|
13
|
+
AssetCloud::FileSystemBucket,
|
14
|
+
AssetCloud::VersionedMemoryBucket,
|
15
|
+
AssetCloud::MemoryBucket,
|
16
|
+
)
|
12
17
|
end
|
13
18
|
|
14
19
|
describe AssetCloud::BucketChain do
|
15
|
-
directory = File.dirname(__FILE__) +
|
20
|
+
directory = File.dirname(__FILE__) + "/files"
|
16
21
|
|
17
22
|
before(:each) do
|
18
|
-
@cloud = ChainedCloud.new(directory,
|
23
|
+
@cloud = ChainedCloud.new(directory, "http://assets/files")
|
19
24
|
@bucket_chain = @cloud.buckets[:stuff]
|
20
25
|
@chained_buckets = @bucket_chain.chained_buckets
|
21
|
-
@chained_buckets.each { |b| b.ls(
|
26
|
+
@chained_buckets.each { |b| b.ls("stuff").each(&:delete) }
|
22
27
|
|
23
28
|
@versioned_stuff = @cloud.buckets[:versioned_stuff]
|
24
29
|
end
|
25
30
|
|
26
31
|
describe ".chain" do
|
27
|
-
it
|
32
|
+
it "should take multiple Bucket classes and return a new Bucket class" do
|
28
33
|
expect(@bucket_chain).to(be_a_kind_of(AssetCloud::BucketChain))
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
32
37
|
describe "#write" do
|
33
|
-
it
|
38
|
+
it "should write to each sub-bucket when everything is kosher and return the result of the first write" do
|
34
39
|
@chained_buckets.each do |bucket|
|
35
|
-
expect(bucket).to(receive(:write).with(
|
40
|
+
expect(bucket).to(receive(:write).with("stuff/foo", "successful creation").and_return("successful creation"))
|
36
41
|
end
|
37
42
|
|
38
|
-
expect(@bucket_chain.write(
|
43
|
+
expect(@bucket_chain.write("stuff/foo", "successful creation")).to(eq("successful creation"))
|
39
44
|
end
|
40
|
-
it
|
41
|
-
expect(@chained_buckets.last).to(receive(:write).with(
|
45
|
+
it "should roll back creation-writes and re-raise an error when a bucket raises one" do
|
46
|
+
expect(@chained_buckets.last).to(receive(:write).with("stuff/foo", "unsuccessful creation").and_raise("hell"))
|
42
47
|
@chained_buckets[0..-2].each do |bucket|
|
43
|
-
expect(bucket).to(receive(:write).with(
|
44
|
-
expect(bucket).to(receive(:delete).with(
|
48
|
+
expect(bucket).to(receive(:write).with("stuff/foo", "unsuccessful creation").and_return(true))
|
49
|
+
expect(bucket).to(receive(:delete).with("stuff/foo").and_return(true))
|
45
50
|
end
|
46
51
|
|
47
|
-
expect { @bucket_chain.write(
|
52
|
+
expect { @bucket_chain.write("stuff/foo", "unsuccessful creation") }.to(raise_error(RuntimeError))
|
48
53
|
end
|
49
|
-
it
|
50
|
-
@bucket_chain.write(
|
54
|
+
it "should roll back update-writes and re-raise an error when a bucket raises one" do
|
55
|
+
@bucket_chain.write("stuff/foo", "original value")
|
51
56
|
|
52
|
-
expect(@chained_buckets.last).to(receive(:write).with(
|
57
|
+
expect(@chained_buckets.last).to(receive(:write).with("stuff/foo", "new value").and_raise("hell"))
|
53
58
|
|
54
|
-
expect { @bucket_chain.write(
|
59
|
+
expect { @bucket_chain.write("stuff/foo", "new value") }.to(raise_error(RuntimeError))
|
55
60
|
@chained_buckets.each do |bucket|
|
56
|
-
expect(bucket.read(
|
61
|
+
expect(bucket.read("stuff/foo")).to(eq("original value"))
|
57
62
|
end
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
61
66
|
describe "#delete" do
|
62
|
-
it
|
63
|
-
@bucket_chain.write(
|
67
|
+
it "should delete from each sub-bucket when everything is kosher" do
|
68
|
+
@bucket_chain.write("stuff/foo", "successful deletion comin' up")
|
64
69
|
|
65
70
|
@chained_buckets.each do |bucket|
|
66
|
-
expect(bucket).to(receive(:delete).with(
|
71
|
+
expect(bucket).to(receive(:delete).with("stuff/foo").and_return(true))
|
67
72
|
end
|
68
73
|
|
69
|
-
@bucket_chain.delete(
|
74
|
+
@bucket_chain.delete("stuff/foo")
|
70
75
|
end
|
71
|
-
it
|
72
|
-
@bucket_chain.write(
|
76
|
+
it "should roll back deletions and re-raise an error when a bucket raises one" do
|
77
|
+
@bucket_chain.write("stuff/foo", "this deletion will fail")
|
73
78
|
|
74
|
-
expect(@chained_buckets.last).to(receive(:delete).with(
|
79
|
+
expect(@chained_buckets.last).to(receive(:delete).with("stuff/foo").and_raise("hell"))
|
75
80
|
@chained_buckets[0..-2].each do |bucket|
|
76
|
-
expect(bucket).to(receive(:delete).with(
|
77
|
-
expect(bucket).to(receive(:write).with(
|
81
|
+
expect(bucket).to(receive(:delete).with("stuff/foo").and_return(true))
|
82
|
+
expect(bucket).to(receive(:write).with("stuff/foo", "this deletion will fail").and_return(true))
|
78
83
|
end
|
79
84
|
|
80
|
-
expect { @bucket_chain.delete(
|
85
|
+
expect { @bucket_chain.delete("stuff/foo") }.to(raise_error(RuntimeError))
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
84
89
|
describe "#read" do
|
85
|
-
it
|
86
|
-
expect(@chained_buckets[0]).to(receive(:read).with(
|
90
|
+
it "should read from only the first available sub-bucket" do
|
91
|
+
expect(@chained_buckets[0]).to(receive(:read).with("stuff/foo").and_raise(NotImplementedError))
|
87
92
|
expect(@chained_buckets[0]).to(receive(:ls).with(nil).and_raise(NoMethodError))
|
88
93
|
expect(@chained_buckets[0]).to(receive(:stat).and_return(:metadata))
|
89
94
|
|
90
|
-
expect(@chained_buckets[1]).to(receive(:read).with(
|
95
|
+
expect(@chained_buckets[1]).to(receive(:read).with("stuff/foo").and_return("bar"))
|
91
96
|
expect(@chained_buckets[1]).to(receive(:ls).with(nil).and_return(:some_assets))
|
92
97
|
expect(@chained_buckets[1]).not_to(receive(:stat))
|
93
98
|
|
@@ -97,59 +102,59 @@ describe AssetCloud::BucketChain do
|
|
97
102
|
expect(bucket).not_to(receive(:stat))
|
98
103
|
end
|
99
104
|
|
100
|
-
expect(@bucket_chain.read(
|
105
|
+
expect(@bucket_chain.read("stuff/foo")).to(eq("bar"))
|
101
106
|
expect(@bucket_chain.ls).to(eq(:some_assets))
|
102
107
|
expect(@bucket_chain.stat).to(eq(:metadata))
|
103
108
|
end
|
104
109
|
end
|
105
110
|
|
106
111
|
describe "#read_version" do
|
107
|
-
it
|
112
|
+
it "should read from only the first available sub-bucket" do
|
108
113
|
buckets = @versioned_stuff.chained_buckets
|
109
114
|
|
110
|
-
expect(buckets[1]).to(receive(:read_version).with(
|
115
|
+
expect(buckets[1]).to(receive(:read_version).with("stuff/foo", 3).and_return("bar"))
|
111
116
|
expect(buckets.last).not_to(receive(:read_version))
|
112
117
|
|
113
|
-
expect(@versioned_stuff.read_version(
|
118
|
+
expect(@versioned_stuff.read_version("stuff/foo", 3)).to(eq("bar"))
|
114
119
|
end
|
115
120
|
end
|
116
121
|
|
117
122
|
describe "#versions" do
|
118
|
-
it
|
123
|
+
it "should read from only the first available sub-bucket" do
|
119
124
|
buckets = @versioned_stuff.chained_buckets
|
120
125
|
|
121
|
-
expect(buckets[1]).to(receive(:versions).with(
|
126
|
+
expect(buckets[1]).to(receive(:versions).with("versioned_stuff/foo").and_return([1, 2, 3]))
|
122
127
|
expect(buckets.last).not_to(receive(:versions))
|
123
128
|
|
124
|
-
expect(@versioned_stuff.versions(
|
129
|
+
expect(@versioned_stuff.versions("versioned_stuff/foo")).to(eq([1, 2, 3]))
|
125
130
|
end
|
126
131
|
end
|
127
132
|
|
128
133
|
describe "with versioned buckets" do
|
129
|
-
it
|
130
|
-
|
131
|
-
@cloud[
|
134
|
+
it "should store and retrieve versions seamlessly" do
|
135
|
+
["one", "two", "three"].each do |content|
|
136
|
+
@cloud["versioned_stuff/foo"] = content
|
132
137
|
end
|
133
|
-
asset = @cloud[
|
134
|
-
expect(asset.value).to(eq(
|
135
|
-
expect(asset.rollback(1).value).to(eq(
|
138
|
+
asset = @cloud["versioned_stuff/foo"]
|
139
|
+
expect(asset.value).to(eq("three"))
|
140
|
+
expect(asset.rollback(1).value).to(eq("one"))
|
136
141
|
expect(asset.versions).to(eq([1, 2, 3]))
|
137
|
-
asset.value =
|
142
|
+
asset.value = "four"
|
138
143
|
asset.store
|
139
144
|
expect(asset.versions).to(eq([1, 2, 3, 4]))
|
140
145
|
end
|
141
146
|
end
|
142
147
|
|
143
|
-
describe
|
144
|
-
it
|
148
|
+
describe "#respond_to?" do
|
149
|
+
it "should return true if any chained buckets respond to the given method" do
|
145
150
|
expect(@bucket_chain.respond_to?(:foo)).to(eq(false))
|
146
151
|
expect(@chained_buckets[1]).to(receive(:respond_to?).with(:bar).and_return(true))
|
147
152
|
expect(@bucket_chain.respond_to?(:bar)).to(eq(true))
|
148
153
|
end
|
149
154
|
end
|
150
155
|
|
151
|
-
describe
|
152
|
-
it
|
156
|
+
describe "#method_missing" do
|
157
|
+
it "should try each bucket" do
|
153
158
|
expect(@chained_buckets[1]).to(receive(:buzz).and_return(true))
|
154
159
|
expect(@chained_buckets[2]).not_to(receive(:buzz))
|
155
160
|
expect(@bucket_chain.buzz).to(eq(true))
|
data/spec/bucket_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
describe AssetCloud::Bucket do
|
5
6
|
before do
|
@@ -8,19 +9,19 @@ describe AssetCloud::Bucket do
|
|
8
9
|
|
9
10
|
describe "operations not supported" do
|
10
11
|
it "#ls not supported" do
|
11
|
-
expect { @bucket.ls(
|
12
|
+
expect { @bucket.ls("foo") }.to(raise_error(NotImplementedError))
|
12
13
|
end
|
13
14
|
|
14
15
|
it "#read(key) not supported" do
|
15
|
-
expect { @bucket.read(
|
16
|
+
expect { @bucket.read("foo") }.to(raise_error(NotImplementedError))
|
16
17
|
end
|
17
18
|
|
18
19
|
it "#write(key, data) not supported" do
|
19
|
-
expect { @bucket.write(
|
20
|
+
expect { @bucket.write("foo", "bar") }.to(raise_error(NotImplementedError))
|
20
21
|
end
|
21
22
|
|
22
23
|
it "#delete(key) not supported" do
|
23
|
-
expect { @bucket.delete(
|
24
|
+
expect { @bucket.delete("foo") }.to(raise_error(NotImplementedError))
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|