kithe 2.0.0.pre.alpha2 → 2.0.0.pre.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/jobs/kithe/create_derivatives_job.rb +2 -2
  3. data/app/models/kithe/asset.rb +82 -154
  4. data/app/models/kithe/asset/derivative_creator.rb +32 -62
  5. data/app/models/kithe/asset/derivative_definition.rb +12 -13
  6. data/app/models/kithe/asset/set_shrine_uploader.rb +64 -0
  7. data/app/models/kithe/collection.rb +0 -6
  8. data/app/models/kithe/model.rb +0 -21
  9. data/app/models/kithe/work.rb +0 -5
  10. data/app/uploaders/kithe/asset_uploader.rb +15 -78
  11. data/lib/kithe/version.rb +4 -1
  12. data/lib/shrine/plugins/kithe_checksum_signatures.rb +41 -0
  13. data/lib/shrine/plugins/kithe_controllable_backgrounding.rb +53 -0
  14. data/lib/shrine/plugins/kithe_derivative_definitions.rb +101 -0
  15. data/lib/shrine/plugins/kithe_derivatives.rb +54 -0
  16. data/lib/shrine/plugins/kithe_determine_mime_type.rb +39 -0
  17. data/lib/shrine/plugins/kithe_persisted_derivatives.rb +161 -0
  18. data/lib/shrine/plugins/kithe_promotion_callbacks.rb +4 -0
  19. data/lib/shrine/plugins/kithe_promotion_directives.rb +33 -3
  20. data/lib/shrine/plugins/kithe_storage_location.rb +53 -4
  21. data/lib/tasks/kithe_tasks.rake +22 -15
  22. data/spec/dummy/log/development.log +867 -0
  23. data/spec/dummy/log/test.log +26005 -0
  24. data/spec/models/kithe/asset/asset_derivatives_spec.rb +137 -0
  25. data/spec/models/kithe/asset/asset_promotion_hooks_spec.rb +26 -5
  26. data/spec/models/kithe/asset/set_shrine_uploader_spec.rb +39 -0
  27. data/spec/models/kithe/asset_spec.rb +9 -59
  28. data/spec/models/kithe/model_spec.rb +0 -32
  29. data/spec/shrine/kithe_accept_remote_url_spec.rb +49 -0
  30. data/spec/shrine/kithe_checksum_signatures_spec.rb +63 -0
  31. data/spec/shrine/kithe_derivative_definitions_spec.rb +303 -0
  32. data/spec/shrine/kithe_persisted_derivatives_spec.rb +424 -0
  33. data/spec/shrine/kithe_storage_location_spec.rb +43 -15
  34. data/spec/spec_helper.rb +7 -6
  35. data/spec/test_support/images/3x3_pixel.jpg +0 -0
  36. data/spec/test_support/shrine_spec_support.rb +2 -1
  37. metadata +23 -23
  38. data/app/models/kithe/asset/derivative_updater.rb +0 -119
  39. data/app/models/kithe/derivative.rb +0 -15
  40. data/app/uploaders/kithe/derivative_uploader.rb +0 -48
  41. data/spec/models/kithe/asset/asset_create_derivatives_spec.rb +0 -320
  42. data/spec/models/kithe/derivative_spec.rb +0 -168
@@ -0,0 +1,63 @@
1
+ require 'rails_helper'
2
+ require 'shrine/plugins/kithe_checksum_signatures'
3
+
4
+ # This kithe plugin is optional, let's make sure it works how we expect
5
+ describe Shrine::Plugins::KitheChecksumSignatures, queue_adpater: :inline do
6
+ temporary_class("ChecksumUploader") do
7
+ Class.new(Kithe::AssetUploader) do
8
+ plugin :kithe_checksum_signatures
9
+ end
10
+ end
11
+
12
+ temporary_class("ChecksumAsset") do
13
+ Class.new(Kithe::Asset) do
14
+ set_shrine_uploader(ChecksumUploader)
15
+ end
16
+ end
17
+
18
+ around do |example|
19
+ original = Kithe::Asset.promotion_directives
20
+ Kithe::Asset.promotion_directives = { promote: :inline }
21
+
22
+ example.run
23
+
24
+ Kithe::Asset.promotion_directives = original
25
+ end
26
+
27
+ it "provides checksum metadata after promotion" do
28
+ asset = ChecksumAsset.create!(title: "test", file: StringIO.new("test"))
29
+ asset.reload
30
+
31
+ expect(asset).to be_stored
32
+ expect(asset.file.metadata.slice("md5", "sha1", "sha512")).to all(be_present)
33
+ end
34
+
35
+ describe "without promotion" do
36
+ around do |example|
37
+ original = Kithe::Asset.promotion_directives
38
+ Kithe::Asset.promotion_directives = { promote: false }
39
+
40
+ example.run
41
+
42
+ Kithe::Asset.promotion_directives = original
43
+ end
44
+
45
+ it "does not extract checksum metadata on cache" do
46
+ asset = ChecksumAsset.create!(title: "test", file: StringIO.new("test"))
47
+ asset.reload
48
+
49
+ expect(asset).not_to be_stored
50
+ expect(asset.file.metadata.slice("md5", "sha1", "sha512")).not_to include(be_present)
51
+ end
52
+ end
53
+
54
+ describe "derivatives" do
55
+ it "do not get checksum metadata" do
56
+ asset = ChecksumAsset.create!(title: "test", file: StringIO.new("test"))
57
+ asset.update_derivative("test", StringIO.new("test deriv"))
58
+
59
+ expect(asset.file_derivatives[:test]).to be_present
60
+ expect(asset.file_derivatives[:test].metadata.slice("md5", "sha1", "sha512")).not_to include(be_present)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,303 @@
1
+ require 'rails_helper'
2
+
3
+ # We just test with a Kithe::Asset class, too much trouble to try to isolate, not
4
+ # worth it I think.
5
+ describe "Shrine::Plugins::KitheDerivativeDefinitions", queue_adapter: :test do
6
+ # promotion inline, disable auto derivatives
7
+ around do |example|
8
+ original = Kithe::Asset.promotion_directives
9
+ Kithe::Asset.promotion_directives = { promote: :inline, create_derivatives: false }
10
+
11
+ example.run
12
+ Kithe::Asset.promotion_directives = original
13
+ end
14
+
15
+ let(:a_jpg_deriv_file) { Kithe::Engine.root.join("spec/test_support/images/2x2_pixel.jpg") }
16
+
17
+ temporary_class("CustomUploader") do
18
+ deriv_src_path = a_jpg_deriv_file
19
+
20
+ Class.new(Kithe::AssetUploader) do
21
+ self::Attacher.define_derivative(:some_data) do |original_file|
22
+ StringIO.new("some one data")
23
+ end
24
+
25
+ self::Attacher.define_derivative(:a_jpg) do |original_file|
26
+ FileUtils.cp(deriv_src_path,
27
+ Kithe::Engine.root.join("spec/test_support/images/2x2_pixel-TEMP.jpg"))
28
+
29
+ File.open(Kithe::Engine.root.join("spec/test_support/images/2x2_pixel-TEMP.jpg"))
30
+ end
31
+ end
32
+ end
33
+
34
+ temporary_class("CustomAsset") do
35
+ Class.new(Kithe::Asset) do
36
+ set_shrine_uploader(CustomUploader)
37
+ end
38
+ end
39
+
40
+ let(:asset) do
41
+ CustomAsset.create(title: "test",
42
+ file: File.open(Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg"))
43
+ )
44
+ end
45
+
46
+ it "normalizes string key to symbol" do
47
+ CustomUploader::Attacher.define_derivative("started_string") { |io| }
48
+ expect(CustomUploader::Attacher.kithe_derivative_definitions.collect(&:key)).to include(:started_string)
49
+ end
50
+
51
+ it "builds derivatives" do
52
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
53
+
54
+ one_deriv = asset.file_derivatives[:some_data]
55
+ expect(one_deriv).to be_present
56
+ expect(one_deriv.read).to eq("some one data")
57
+
58
+ jpg_deriv = asset.file_derivatives[:a_jpg]
59
+ expect(jpg_deriv.read).to eq(File.binread(a_jpg_deriv_file))
60
+ expect(jpg_deriv.storage_key).to eq(:kithe_derivatives)
61
+ end
62
+
63
+ describe "attacher argument to block" do
64
+ let(:monitoring_proc) do
65
+ proc do |original_file, attacher:|
66
+ expect(original_file.kind_of?(File) || original_file.kind_of?(Tempfile)).to be(true)
67
+ expect(original_file.path).to be_present
68
+ expect(original_file.read).to eq(asset.file.read)
69
+
70
+ expect(attacher).to be_present
71
+ expect(attacher).to be_kind_of(Shrine::Attacher)
72
+ expect(attacher.record).to eq(asset)
73
+ expect(attacher.file).to be_kind_of(Shrine::UploadedFile)
74
+ nil
75
+ end
76
+ end
77
+
78
+ before do
79
+ # hacky confusing way to set this up for testing, sorry.
80
+ CustomUploader::Attacher.kithe_derivative_definitions = []
81
+ CustomUploader::Attacher.define_derivative(:some_data, &monitoring_proc)
82
+ end
83
+
84
+ it "as expected" do
85
+ expect(monitoring_proc).to receive(:call).and_call_original
86
+
87
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
88
+ expect(asset.file_derivatives.length).to eq(0)
89
+ end
90
+
91
+ describe "as **kwargs" do
92
+ let(:monitoring_proc) do
93
+ proc do |original_file, **kwargs|
94
+ expect(original_file.kind_of?(File) || original_file.kind_of?(Tempfile)).to be(true)
95
+ expect(original_file.path).to be_present
96
+ expect(original_file.read).to eq(asset.file.read)
97
+
98
+ # It really has to be a local file with a path, not just an IO.
99
+ # Kithe wants to guarantee this, whether or not shrine does.
100
+ expect(original_file).to respond_to(:path)
101
+
102
+ expect(kwargs[:attacher]).to be_present
103
+ expect(kwargs[:attacher]).to eq(asset.file_attacher)
104
+
105
+ nil
106
+ end
107
+ end
108
+
109
+ it "as expected" do
110
+ expect(monitoring_proc).to receive(:call).and_call_original
111
+
112
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
113
+ expect(asset.file_derivatives.length).to eq(0)
114
+ end
115
+ end
116
+ end
117
+
118
+
119
+ describe "default_create false" do
120
+ let(:monitoring_proc) { proc { |asset| } }
121
+
122
+ before do
123
+ # hacky confusing way to set this up for testing, sorry.
124
+ CustomUploader::Attacher.kithe_derivative_definitions = []
125
+ CustomUploader::Attacher.define_derivative(:some_data, default_create: false, &monitoring_proc)
126
+ end
127
+
128
+ it "is not run automatically" do
129
+ expect(monitoring_proc).not_to receive(:call)
130
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
131
+ end
132
+ end
133
+
134
+ describe "only/except" do
135
+ let(:monitoring_proc1) { proc { |asset| StringIO.new("one") } }
136
+ let(:monitoring_proc2) { proc { |asset| StringIO.new("two") } }
137
+ let(:monitoring_proc3) { proc { |asset| StringIO.new("three") } }
138
+
139
+ before do
140
+ # hacky confusing way to set this up for testing, sorry.
141
+ CustomUploader::Attacher.kithe_derivative_definitions = []
142
+ CustomUploader::Attacher.define_derivative(:one, default_create: false, &monitoring_proc1)
143
+ CustomUploader::Attacher.define_derivative(:two, &monitoring_proc2)
144
+ CustomUploader::Attacher.define_derivative(:three, &monitoring_proc2)
145
+ end
146
+
147
+ it "can call with only" do
148
+ expect(monitoring_proc1).to receive(:call).and_call_original
149
+ expect(monitoring_proc2).to receive(:call).and_call_original
150
+ expect(monitoring_proc3).not_to receive(:call)
151
+
152
+ # except string or symbol
153
+ asset.file_attacher.create_derivatives(:kithe_derivatives, only: [:one, "two"])
154
+
155
+ expect(asset.file_derivatives.keys).to match([:one, :two])
156
+ end
157
+
158
+ it "can call with except" do
159
+ expect(monitoring_proc1).not_to receive(:call)
160
+ expect(monitoring_proc2).to receive(:call).and_call_original
161
+ expect(monitoring_proc3).not_to receive(:call)
162
+
163
+ asset.file_attacher.create_derivatives(:kithe_derivatives, except: [:three])
164
+
165
+ # :one was default_create:false, and we said except: :three
166
+ expect(asset.file_derivatives.keys).to eq([:two])
167
+ end
168
+
169
+ it "can call with except as string" do
170
+ expect(monitoring_proc1).not_to receive(:call)
171
+ expect(monitoring_proc2).to receive(:call).and_call_original
172
+ expect(monitoring_proc3).not_to receive(:call)
173
+
174
+ asset.file_attacher.create_derivatives(:kithe_derivatives, except: ["three"])
175
+
176
+ # :one was default_create:false, and we said except: :three
177
+ expect(asset.file_derivatives.keys).to eq([:two])
178
+ end
179
+
180
+ it "can call with only and except" do
181
+ expect(monitoring_proc1).to receive(:call).and_call_original
182
+ expect(monitoring_proc2).to receive(:call).and_call_original
183
+ expect(monitoring_proc3).not_to receive(:call)
184
+
185
+ # string version of except why not
186
+ asset.file_attacher.create_derivatives(:kithe_derivatives, only: [:one, :two], except: :three)
187
+
188
+ expect(asset.file_derivatives.keys).to eq([:one, :two])
189
+ end
190
+ end
191
+
192
+
193
+ describe "content_type filters" do
194
+ before do
195
+ # hacky confusing way to set this up for testing, sorry.
196
+ CustomUploader::Attacher.kithe_derivative_definitions = []
197
+ CustomUploader::Attacher.define_derivative(:never_called, content_type: "nothing/nothing") { |o| StringIO.new("never") }
198
+ CustomUploader::Attacher.define_derivative(:gated_positive, content_type: "image/jpeg") { |o| StringIO.new("gated positive") }
199
+ CustomUploader::Attacher.define_derivative(:gated_positive_main_type, content_type: "image") { |o| StringIO.new("gated positive") }
200
+ end
201
+
202
+ it "does not call if content type does not match" do
203
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
204
+ expect(asset.file_derivatives.keys).not_to include(:never_called)
205
+ end
206
+
207
+ it "calls for exact content type match" do
208
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
209
+ expect(asset.file_derivatives.keys).to include(:gated_positive)
210
+ end
211
+
212
+ it "calls for main content type match" do
213
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
214
+ expect(asset.file_derivatives.keys).to include(:gated_positive_main_type)
215
+ end
216
+
217
+ describe "as array" do
218
+ before do
219
+ # hacky confusing way to set this up for testing, sorry.
220
+ CustomUploader::Attacher.kithe_derivative_definitions = []
221
+ CustomUploader::Attacher.define_derivative(:never_called, content_type: ["nothing/nothing", "also/nothing"]) { |o| StringIO.new("never") }
222
+ CustomUploader::Attacher.define_derivative(:gated_positive, content_type: ["image/jpeg", "something/else"]) { |o| StringIO.new("gated positive") }
223
+ end
224
+
225
+ it "calls for one match" do
226
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
227
+ expect(asset.file_derivatives.keys).to eq([:gated_positive])
228
+ end
229
+ end
230
+
231
+ describe "conflicting types" do
232
+ let(:unfiltered) { proc { |asset| StringIO.new("unfiltered") } }
233
+ let(:image) { proc { |asset| StringIO.new("image") } }
234
+ let(:image_jpeg) { proc { |asset| StringIO.new("image/jpeg") } }
235
+
236
+ before do
237
+ # hacky confusing way to set this up for testing, sorry.
238
+ CustomUploader::Attacher.kithe_derivative_definitions = []
239
+ CustomUploader::Attacher.define_derivative(:key, &unfiltered)
240
+ CustomUploader::Attacher.define_derivative(:key, content_type: "image/jpeg", &image_jpeg)
241
+ CustomUploader::Attacher.define_derivative(:key, content_type: "image", &image)
242
+ end
243
+
244
+ it "takes most specific" do
245
+ expect(unfiltered).not_to receive(:call)
246
+ expect(image).not_to receive(:call)
247
+ expect(image_jpeg).to receive(:call).and_call_original
248
+
249
+ asset.file_attacher.create_derivatives(:kithe_derivatives)
250
+ expect(asset.file_derivatives.count).to eq(1)
251
+
252
+
253
+ expect(asset.file_derivatives.keys).to eq([:key])
254
+ expect(asset.file_derivatives[:key].read). to eq("image/jpeg")
255
+ end
256
+ end
257
+ end
258
+
259
+ describe "lazy creation" do
260
+ before do
261
+ # Create existing derivatives for existing definitions, which we assume exist
262
+ expect(CustomUploader::Attacher.kithe_derivative_definitions).to be_present
263
+
264
+ CustomUploader::Attacher.kithe_derivative_definitions.collect(&:key).each do |key|
265
+ asset.file_attacher.add_persisted_derivatives({key => StringIO.new("#{key} original")})
266
+ end
267
+ end
268
+
269
+ it "does not re-create" do
270
+ derivatives_pre_creation = asset.file_derivatives
271
+
272
+ asset.file_attacher.create_derivatives(:kithe_derivatives, lazy: true)
273
+ derivatives_post_creation = asset.file_derivatives
274
+
275
+ expect(derivatives_post_creation).to eq(derivatives_pre_creation)
276
+ end
277
+ end
278
+
279
+ describe "#remove_derivative_definition!" do
280
+ let(:defined_derivative_key) do
281
+ CustomUploader::Attacher.defined_derivative_keys.first.tap do |key|
282
+ expect(key).to be_present
283
+ end
284
+ end
285
+
286
+ it "can remove by string" do
287
+ expect {
288
+ CustomUploader::Attacher.remove_derivative_definition!(defined_derivative_key.to_s)
289
+ }.to change { CustomUploader::Attacher.defined_derivative_keys.count }.from(2).to(1)
290
+ end
291
+
292
+ it "can remove by symbol" do
293
+ expect {
294
+ CustomUploader::Attacher.remove_derivative_definition!(defined_derivative_key.to_sym)
295
+ }.to change { CustomUploader::Attacher.defined_derivative_keys.count }.from(2).to(1)
296
+ end
297
+
298
+ it "can remove multiple args" do
299
+ CustomUploader::Attacher.remove_derivative_definition!(*CustomUploader::Attacher.defined_derivative_keys)
300
+ expect(CustomUploader::Attacher.defined_derivative_keys).to eq([])
301
+ end
302
+ end
303
+ end
@@ -0,0 +1,424 @@
1
+ require 'rails_helper'
2
+ require 'shrine/plugins/kithe_persisted_derivatives'
3
+
4
+ # We just test with a Kithe::Asset class, too much trouble to try to isolate, not
5
+ # worth it I think.
6
+ describe Shrine::Plugins::KithePersistedDerivatives, queue_adapter: :test do
7
+ # promotion inline, disable auto derivatives
8
+ around do |example|
9
+ original = Kithe::Asset.promotion_directives
10
+ Kithe::Asset.promotion_directives = { promote: :inline, create_derivatives: false }
11
+
12
+ example.run
13
+ Kithe::Asset.promotion_directives = original
14
+ end
15
+
16
+ # Need to make a new copy, because shrine likes deleting derivatives!
17
+ def sample_deriv_file!(path = Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg"))
18
+ tempfile = Tempfile.new
19
+ IO.copy_stream(File.open(path), tempfile)
20
+
21
+ tempfile
22
+ end
23
+
24
+ let(:sample_orig_path) { Kithe::Engine.root.join("spec/test_support/images/2x2_pixel.jpg") }
25
+ let(:another_sample_orig_path) { Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg") }
26
+
27
+ let(:asset) { Kithe::Asset.create!(title: "test", file: File.open(sample_orig_path))}
28
+
29
+ describe "#add_persisted_derivatives" do
30
+ it "can add and persist" do
31
+ asset.file_attacher.add_persisted_derivatives(sample: sample_deriv_file!)
32
+
33
+ expect(asset.changed?).to be(false)
34
+ expect(asset.file_derivatives[:sample]).to be_present
35
+ expect(asset.file_derivatives[:sample].storage_key).to eq(:kithe_derivatives)
36
+ expect(asset.file_derivatives[:sample].exists?).to be(true)
37
+
38
+ # sanity check
39
+ asset.reload
40
+ expect(asset.file_derivatives[:sample]).to be_present
41
+ end
42
+
43
+ it "can avoid deleting deriv file" do
44
+ file = sample_deriv_file!
45
+ asset.file_attacher.add_persisted_derivatives({sample: file}, delete: false)
46
+
47
+ expect(File.exists?(file.path)).to eq(true)
48
+ end
49
+
50
+ it "can use custom storage" do
51
+ file = sample_deriv_file!
52
+ asset.file_attacher.add_persisted_derivatives({sample: file}, storage: :cache)
53
+
54
+ asset.reload
55
+ expect(asset.file_derivatives[:sample]).to be_present
56
+ expect(asset.file_derivatives[:sample].storage_key).to eq(:cache)
57
+ end
58
+
59
+ it "can supply custom metadata" do
60
+ file = sample_deriv_file!
61
+ asset.file_attacher.add_persisted_derivatives({sample: file}, metadata: { extra: "value" })
62
+
63
+ asset.reload
64
+
65
+ expect(asset.file_derivatives[:sample].metadata["extra"]).to eq("value")
66
+ # and still has default metadata
67
+ expect(asset.file_derivatives[:sample].metadata["size"]).to be_present
68
+ end
69
+
70
+ describe "model with unsaved changes" do
71
+ before do
72
+ asset.title = "changed title"
73
+ end
74
+
75
+ it "will refuse" do
76
+ expect {
77
+ asset.file_attacher.add_persisted_derivatives(sample: sample_deriv_file!)
78
+ }.to raise_error(TypeError)
79
+ end
80
+
81
+ it "can be forced" do
82
+ asset.file_attacher.add_persisted_derivatives({sample: sample_deriv_file!}, allow_other_changes: true)
83
+
84
+ expect(asset.changed?).to be(false)
85
+ asset.reload
86
+ expect(asset.title).to eq("changed title")
87
+ expect(asset.file_derivatives[:sample]).to be_present
88
+ end
89
+ end
90
+
91
+ describe "unsaved model" do
92
+ let(:asset) { Kithe::Asset.new(title: "test", file: File.open(sample_orig_path)) }
93
+
94
+ it "refuses even with other_changes: true" do
95
+ expect {
96
+ asset.file_attacher.add_persisted_derivatives({sample: sample_deriv_file!}, allow_other_changes: true)
97
+ }.to raise_error(TypeError)
98
+ end
99
+
100
+ describe "with an existing derivative" do
101
+ before do
102
+ asset.save!
103
+ asset.file_attacher.add_derivative("key", StringIO.new("existing"))
104
+ asset.save!
105
+ end
106
+
107
+ it "replaces" do
108
+ existing_storage = asset.file_derivatives[:key]
109
+ expect(existing_storage.exists?).to be(true)
110
+
111
+ asset.file_attacher.add_persisted_derivatives({"key" => StringIO.new("new")})
112
+ expect(asset.file_derivatives[:key].read).to eq("new")
113
+ expect(existing_storage.exists?).to be(false)
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "Original deleted before derivatives can be created" do
119
+ before do
120
+ # delete it out from under us
121
+ Kithe::Model.where(id: asset.id).delete_all
122
+ end
123
+
124
+ it "doesn't complain and cleans up file" do
125
+
126
+ # asset is no longer in the DB.
127
+ # Let's try and create derivatives for it:
128
+ file = sample_deriv_file!
129
+ local_file_path = file.path
130
+
131
+ expect(asset.file_attacher.add_persisted_derivatives(sample: file)).to be(false)
132
+
133
+ expect(File.exist?(local_file_path)).to be(false)
134
+ end
135
+ end
136
+
137
+ describe "Original changed before derivatives can be created" do
138
+ before do
139
+ asset # load
140
+
141
+ # Change what's in the db for this asset, without changing the in-memory
142
+ # asset
143
+ another_copy = Kithe::Asset.find(asset.id)
144
+ another_copy.file = File.open(another_sample_orig_path)
145
+ another_copy.save!
146
+ end
147
+
148
+ it "doesn't add derivative and cleans up file" do
149
+ # asset in DB has different file attachment
150
+ # Let's try and create derivatives for it:
151
+ file = sample_deriv_file!
152
+ local_file_path = file.path
153
+
154
+ expect(asset.file_attacher.add_persisted_derivatives(new_try: file)).to be(false)
155
+
156
+
157
+ expect(asset.changed?).to be(false)
158
+ expect(asset.file_derivatives[:new_try]).to be_nil
159
+ asset.reload
160
+ expect(asset.file_derivatives[:new_try]).to be_nil
161
+
162
+ expect(File.exist?(local_file_path)).to be(false)
163
+ end
164
+ end
165
+
166
+ describe "concurrent derivative changes" do
167
+ let(:original_one) { sample_deriv_file!(Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg")) }
168
+ let(:original_two) { sample_deriv_file!(Kithe::Engine.root.join("spec/test_support/images/2x2_pixel.jpg")) }
169
+
170
+ let(:new_two) { sample_deriv_file!(Kithe::Engine.root.join("spec/test_support/images/3x3_pixel.jpg")) }
171
+ let(:new_three) { sample_deriv_file!(Kithe::Engine.root.join("spec/test_support/images/3x3_pixel.jpg")) }
172
+
173
+ before do
174
+ # make sure our test is setup to test what we want
175
+ original_two.rewind; new_two.rewind
176
+ expect(original_two.read).not_to eq(new_two.read)
177
+ original_two.rewind; new_two.rewind
178
+
179
+ asset # load
180
+
181
+ # change what derivatives are in db for this asset, without changing
182
+ # the in-memory asset
183
+ another_copy = Kithe::Asset.find(asset.id)
184
+ another_copy.file_attacher.add_derivatives({
185
+ one: original_one,
186
+ two: original_two
187
+ }, delete: false)
188
+ another_copy.save!
189
+
190
+ # Make sure we set up what we expected
191
+ another_copy.reload
192
+ expect(another_copy.file_derivatives[:one]).to be_present
193
+ expect(another_copy.file_derivatives[:two]).to be_present
194
+ end
195
+
196
+ it "merges changes in safely" do
197
+ expect(asset.file_derivatives.keys).to be_empty
198
+
199
+ asset.file_attacher.add_persisted_derivatives({two: new_two, three: new_three}, delete: false)
200
+
201
+ expect(asset.changed?).to be(false)
202
+ expect(asset.file_derivatives.keys).to match([:one, :two, :three])
203
+ expect(asset.file_derivatives[:two].read).to eq(File.binread(new_two.path))
204
+ expect(asset.file_derivatives[:three].read).to eq(File.binread(new_three.path))
205
+ end
206
+ end
207
+ end
208
+
209
+ describe "#create_persisted_derivatives" do
210
+ temporary_class("AssetSubclassUploader") do
211
+ call_fakeio = method(:fakeio) # weird closure issue
212
+
213
+ Class.new(Kithe::AssetUploader) do
214
+ self::Attacher.derivatives do |original, **options|
215
+ {
216
+ one: call_fakeio.("one"),
217
+ original_reflected: call_fakeio.(original.read)
218
+ }
219
+ end
220
+
221
+ self::Attacher.derivatives(:options) do |original, **options|
222
+ {
223
+ options_one: call_fakeio.("one"),
224
+ options_reflected: call_fakeio.(options.to_s)
225
+ }
226
+ end
227
+ end
228
+ end
229
+
230
+ temporary_class("AssetSubclass") do
231
+ Class.new(Kithe::Asset) do
232
+ set_shrine_uploader(AssetSubclassUploader)
233
+ end
234
+ end
235
+
236
+ let(:asset) { AssetSubclass.create!(title: "test", file: File.open(sample_orig_path))}
237
+
238
+ it "creates derivatives" do
239
+ # we're not gonna test concurrency safety, counting on add_persisted_derivatives
240
+ # for that, but let's make sure
241
+ expect(asset.file_attacher).to receive(:add_persisted_derivatives).and_call_original
242
+
243
+ asset.file_attacher.create_persisted_derivatives
244
+
245
+ expect(asset.changed?).to be(false)
246
+ expect(asset.file_derivatives.keys).to match([:one, :original_reflected])
247
+ asset.reload
248
+ expect(asset.file_derivatives[:one].read).to eq("one")
249
+ expect(asset.file_derivatives[:one].storage_key).to eq(:kithe_derivatives)
250
+ expect(asset.file_derivatives[:original_reflected].read).to eq(File.binread(sample_orig_path))
251
+ expect(asset.file_derivatives[:original_reflected].storage_key).to eq(:kithe_derivatives)
252
+ end
253
+
254
+ describe "with custom source" do
255
+ let(:string_io_source) { StringIO.new("pretend data") }
256
+
257
+ it "works with custom source as StringIO" do
258
+ asset.file_attacher.create_persisted_derivatives(:options, string_io_source)
259
+ expect(asset.file_derivatives).to be_present
260
+ end
261
+
262
+ it "works with custom source StringIO as only arg" do
263
+ asset.file_attacher.create_persisted_derivatives(string_io_source)
264
+
265
+ string_io_source.rewind
266
+ expect(asset.file_derivatives[:original_reflected].read).to eq(string_io_source.read)
267
+ end
268
+ end
269
+
270
+ describe "for an asset with nil file_data" do
271
+ let(:asset) { AssetSubclass.create!(title: "blank") }
272
+
273
+ it "no-ops" do
274
+ expect(asset.file_attacher.create_persisted_derivatives).to be(false)
275
+ end
276
+ end
277
+
278
+ describe "for an asset with missing original" do
279
+ let(:asset) { AssetSubclass.create!(title: "blank", file_data: { storage: "cache", id: "not_found"}) }
280
+
281
+ it "raises" do
282
+ expect(asset.file.exists?).to be(false)
283
+
284
+ # Not necessarily what kithe 1.x did, but this seems better...
285
+ expect {
286
+ asset.file_attacher.create_persisted_derivatives
287
+ }.to raise_error(Shrine::FileNotFound)
288
+ end
289
+ end
290
+
291
+ it "can call custom processor" do
292
+ asset.file_attacher.create_persisted_derivatives(:options)
293
+
294
+ expect(asset.file_derivatives.keys).to match([:options_one, :options_reflected])
295
+ end
296
+
297
+ it "can pass processor options" do
298
+ asset.file_attacher.create_persisted_derivatives(:options, arg1: "value1", arg2: "value2")
299
+
300
+ expect(asset.file_derivatives[:options_reflected].read).to eq({arg1: "value1", arg2: "value2"}.to_s)
301
+ end
302
+
303
+ it "can customize :storage" do
304
+ asset.file_attacher.create_persisted_derivatives(:options, storage: :cache, arg1: "value1", arg2: "value2")
305
+
306
+ expect(asset.file_derivatives[:options_reflected].read).to eq({arg1: "value1", arg2: "value2"}.to_s)
307
+ expect(asset.file_derivatives[:options_reflected].storage_key).to eq(:cache)
308
+ end
309
+
310
+ describe "model with unsaved changes" do
311
+ before do
312
+ asset.title = "changed title"
313
+ end
314
+
315
+ it "will refuse" do
316
+ expect {
317
+ asset.file_attacher.create_persisted_derivatives
318
+ }.to raise_error(TypeError)
319
+ end
320
+
321
+ it "can be forced" do
322
+ asset.file_attacher.create_persisted_derivatives(allow_other_changes: true)
323
+
324
+ expect(asset.changed?).to be(false)
325
+ asset.reload
326
+ expect(asset.title).to eq("changed title")
327
+ expect(asset.file_derivatives.keys).to match([:one, :original_reflected])
328
+ end
329
+ end
330
+ end
331
+
332
+ describe "#remove_persisted_derivatives" do
333
+ before do
334
+ asset.file_attacher.add_persisted_derivatives(
335
+ sample1: fakeio("sample 1"),
336
+ sample2: fakeio("sample 2")
337
+ )
338
+ end
339
+
340
+ it "can remove" do
341
+ removed = asset.file_attacher.remove_persisted_derivatives(:sample1)
342
+
343
+ expect(asset.changed?).to eq(false)
344
+ expect(asset.file_derivatives.keys).to eq([:sample2])
345
+ asset.reload
346
+ expect(asset.file_derivatives.keys).to eq([:sample2])
347
+
348
+ expect(removed).to be_kind_of(Array)
349
+ expect(removed.length).to eq(1)
350
+ expect(removed.first).to be_kind_of(Shrine::UploadedFile)
351
+ expect(removed.first.exists?).to be(false)
352
+ end
353
+
354
+ describe "if someone else removed first" do
355
+ before do
356
+ another_copy = asset.class.find(asset.id)
357
+ another_copy.file_attacher.remove_derivative(:sample1)
358
+ another_copy.save!
359
+ another_copy.reload
360
+ expect(another_copy.file_derivatives.keys).to eq([:sample2])
361
+
362
+ expect(asset.file_derivatives.keys).to match([:sample1, :sample2])
363
+ end
364
+
365
+ it "doesn't complain" do
366
+ asset.file_attacher.remove_persisted_derivatives(:sample1)
367
+ expect(asset.changed?).to eq(false)
368
+ expect(asset.file_derivatives.keys).to eq([:sample2])
369
+ end
370
+ end
371
+
372
+ describe "someone else added another derivative" do
373
+ before do
374
+ another_copy = asset.class.find(asset.id)
375
+ another_copy.file_attacher.add_persisted_derivatives({:sample3 => fakeio("sample 3")})
376
+ another_copy.reload
377
+ expect(another_copy.file_derivatives.keys).to match([:sample1, :sample2, :sample3])
378
+
379
+ expect(asset.file_derivatives.keys).to match([:sample1, :sample2])
380
+ end
381
+
382
+ it "deletes without deleting newly added" do
383
+ asset.file_attacher.remove_persisted_derivatives(:sample1)
384
+
385
+ expect(asset.changed?).to eq(false)
386
+ expect(asset.file_derivatives.keys).to eq([:sample2, :sample3])
387
+ end
388
+ end
389
+
390
+ describe "model deleted from under us" do
391
+ before do
392
+ another_copy = asset.class.find(asset.id)
393
+ another_copy.destroy!
394
+ end
395
+
396
+ it "silently no-ops" do
397
+ result = asset.file_attacher.remove_persisted_derivatives(:sample1)
398
+ expect(result).to eq(false)
399
+ end
400
+ end
401
+
402
+ describe "model with unsaved changes" do
403
+ before do
404
+ asset.title = "changed title"
405
+ end
406
+
407
+ it "will refuse" do
408
+ expect {
409
+ asset.file_attacher.remove_persisted_derivatives(:sample1)
410
+ }.to raise_error(TypeError)
411
+ end
412
+
413
+ it "can be forced" do
414
+ asset.file_attacher.remove_persisted_derivatives(:sample1, allow_other_changes: true)
415
+
416
+ expect(asset.changed?).to be(false)
417
+ asset.reload
418
+ expect(asset.title).to eq("changed title")
419
+ expect(asset.file_derivatives.keys).to eq([:sample2])
420
+ end
421
+ end
422
+
423
+ end
424
+ end