resizing 1.2.2 → 1.3.1

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +73 -0
  3. data/.devcontainer/compose.yaml +58 -0
  4. data/.devcontainer/devcontainer-lock.json +9 -0
  5. data/.devcontainer/devcontainer.json +32 -0
  6. data/.devcontainer/post-create.sh +41 -0
  7. data/.github/copilot-instructions.md +1 -0
  8. data/.github/labeler.yml +28 -0
  9. data/.github/release.yml +35 -0
  10. data/.github/workflows/labeler.yml +20 -0
  11. data/.github/workflows/lint.yml +37 -0
  12. data/.github/workflows/test.yml +16 -9
  13. data/AGENTS.md +1 -0
  14. data/CHANGELOG.md +3 -0
  15. data/CLAUDE.md +68 -0
  16. data/Gemfile +9 -3
  17. data/README.md +114 -2
  18. data/Rakefile +5 -7
  19. data/bin/setup +3 -0
  20. data/git-hooks/pre-push +6 -0
  21. data/git-hooks/pre-push-ruby.sh +48 -0
  22. data/lib/resizing/carrier_wave/callback_file.rb +88 -0
  23. data/lib/resizing/carrier_wave/storage/file.rb +84 -36
  24. data/lib/resizing/carrier_wave/storage/remote.rb +7 -3
  25. data/lib/resizing/carrier_wave.rb +41 -6
  26. data/lib/resizing/client.rb +0 -1
  27. data/lib/resizing/configurable.rb +1 -1
  28. data/lib/resizing/configuration.rb +40 -10
  29. data/lib/resizing/mock_client.rb +23 -7
  30. data/lib/resizing/public_id.rb +3 -2
  31. data/lib/resizing/version.rb +1 -1
  32. data/lib/resizing.rb +0 -1
  33. data/resizing.gemspec +3 -3
  34. data/test/resizing/carrier_wave/storage/file_test.rb +455 -9
  35. data/test/resizing/carrier_wave/storage/remote_test.rb +91 -9
  36. data/test/resizing/carrier_wave_cache_callbacks_test.rb +224 -0
  37. data/test/resizing/carrier_wave_callback_file_test.rb +77 -0
  38. data/test/resizing/carrier_wave_test.rb +201 -26
  39. data/test/resizing/carrier_wave_uploader_test.rb +211 -0
  40. data/test/resizing/client_test.rb +324 -25
  41. data/test/resizing/configuration_test.rb +235 -10
  42. data/test/resizing/http_clientable_test.rb +27 -0
  43. data/test/resizing/mock_client_test.rb +111 -1
  44. data/test/resizing/public_id_test.rb +96 -0
  45. data/test/resizing_module_test.rb +110 -0
  46. data/test/resizing_test.rb +8 -0
  47. data/test/test_helper.rb +297 -9
  48. metadata +33 -9
data/resizing.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = 'Client and utilities for Resizing '
13
13
  spec.homepage = 'https://github.com/jksy/resizing-gem'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 3.0.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.1.0')
16
16
 
17
17
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
18
 
@@ -26,8 +26,8 @@ Gem::Specification.new do |spec|
26
26
  `git ls-files -z`.split("\x0")
27
27
  end
28
28
  spec.require_paths = ['lib']
29
- spec.add_runtime_dependency 'faraday', '~> 2.3'
30
- spec.add_runtime_dependency 'faraday-multipart'
29
+ spec.add_runtime_dependency 'faraday', '>= 1.0', '< 3'
30
+ spec.add_runtime_dependency 'faraday-multipart', '>= 1.0'
31
31
  spec.add_development_dependency 'carrierwave', '~> 2.2.5'
32
32
  spec.add_development_dependency 'fog-aws'
33
33
  spec.add_development_dependency 'minitest', '~> 5.16'
@@ -1,21 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'test_helper'
4
+ require 'tempfile'
4
5
 
5
6
  module Resizing
6
7
  module CarrierWave
7
8
  module Storage
8
9
  class FileTest < Minitest::Test
10
+ include VCRRequestAssertions
11
+ include FakeApiClientAssertions
12
+ include ResizingTestConfiguration
13
+
9
14
  def setup
10
- @configuration_template = {
11
- image_host: 'http://192.168.56.101:5000',
12
- video_host: 'http://192.168.56.101:5000',
13
- project_id: 'e06e710d-f026-4dcf-b2c0-eab0de8bb83f',
14
- secret_token: 'ewbym2r1pk49x1d2lxdbiiavnqp25j2kh00hsg3koy0ppm620x5mhlmgl3rq5ci8',
15
- open_timeout: 10,
16
- response_timeout: 20
17
- }
18
- Resizing.configure = @configuration_template
15
+ configure_resizing
19
16
  end
20
17
 
21
18
  def teardown
@@ -165,6 +162,455 @@ module Resizing
165
162
  file.delete
166
163
  end
167
164
  end
165
+
166
+ # ============================================================
167
+ # delete の詳細な挙動 (Resizing::Client を偽クライアントに差し替えて検証)
168
+ # ============================================================
169
+
170
+ IDENTIFIER = '/projects/e06e710d-f026-4dcf-b2c0-eab0de8bb83f/upload/images/14ea7aac-a194-4330-931f-6b562aec413d/v_8c5lEhDB5RT3PZp1Fn5PYGm9YVx_x0e'
171
+ IMAGE_ID = '14ea7aac-a194-4330-931f-6b562aec413d'
172
+ OTHER_IDENTIFIER = '/projects/e06e710d-f026-4dcf-b2c0-eab0de8bb83f/upload/images/new-image-id-2222-2222-222222222222/v2'
173
+ NOT_FOUND_RESPONSE = {
174
+ 'error' => 'ActiveRecord::RecordNotFound',
175
+ 'message' => "Upload::Image##{IMAGE_ID} not found(no record)"
176
+ }.freeze
177
+
178
+ def model_with_column(value)
179
+ model = TestModel.new
180
+ model.send(:write_attribute, :resizing_picture, value)
181
+ model
182
+ end
183
+
184
+ def test_delete_clears_column_when_deleted_image_is_current
185
+ model = model_with_column(IDENTIFIER)
186
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
187
+
188
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
189
+ file.delete
190
+ assert_equal [IMAGE_ID], fake.deleted_ids
191
+ end
192
+
193
+ assert_nil model.read_attribute(:resizing_picture)
194
+ end
195
+
196
+ def test_delete_keeps_column_when_deleting_previous_image_after_update
197
+ # 画像更新時: カラムは新しい画像を指しているが、削除対象は古い画像なのでカラムは消さない
198
+ model = model_with_column(OTHER_IDENTIFIER)
199
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
200
+
201
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
202
+ file.delete
203
+ assert_equal [IMAGE_ID], fake.deleted_ids
204
+ end
205
+
206
+ assert_equal OTHER_IDENTIFIER, model.read_attribute(:resizing_picture)
207
+ end
208
+
209
+ def test_delete_treats_not_found_as_success_and_clears_column
210
+ model = model_with_column(IDENTIFIER)
211
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
212
+
213
+ with_fake_api_client(NOT_FOUND_RESPONSE) do
214
+ assert_nil file.delete
215
+ end
216
+
217
+ assert_nil model.read_attribute(:resizing_picture)
218
+ end
219
+
220
+ def test_delete_treats_not_found_of_previous_image_without_clearing_column
221
+ model = model_with_column(OTHER_IDENTIFIER)
222
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
223
+
224
+ with_fake_api_client(NOT_FOUND_RESPONSE) { file.delete }
225
+
226
+ assert_equal OTHER_IDENTIFIER, model.read_attribute(:resizing_picture)
227
+ end
228
+
229
+ def test_delete_raises_api_error_when_response_id_does_not_match
230
+ model = model_with_column(IDENTIFIER)
231
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
232
+
233
+ with_fake_api_client({ 'id' => 'someone-else' }) do
234
+ assert_raises(Resizing::APIError) { file.delete }
235
+ end
236
+
237
+ # 失敗時はカラムを変更しない
238
+ assert_equal IDENTIFIER, model.read_attribute(:resizing_picture)
239
+ end
240
+
241
+ def test_delete_uses_column_value_when_constructed_without_identifier
242
+ # remove! の経路では識別子なしで File が生成され、モデルのカラム値から削除対象を決める
243
+ model = model_with_column(IDENTIFIER)
244
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
245
+
246
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
247
+ file.delete
248
+ assert_equal [IMAGE_ID], fake.deleted_ids
249
+ end
250
+
251
+ assert_nil model.read_attribute(:resizing_picture)
252
+ end
253
+
254
+ def test_delete_uses_previous_column_value_when_column_has_unsaved_change
255
+ # attribute_was: カラムが変更済み (保存前) の場合は変更前の値の画像を削除する
256
+ model = model_with_column(IDENTIFIER)
257
+ model.save!
258
+ model.send(:write_attribute, :resizing_picture, OTHER_IDENTIFIER)
259
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
260
+
261
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
262
+ file.delete
263
+ assert_equal [IMAGE_ID], fake.deleted_ids
264
+ end
265
+
266
+ # 削除したのは古い画像なので、新しい値はそのまま残る
267
+ assert_equal OTHER_IDENTIFIER, model.read_attribute(:resizing_picture)
268
+ end
269
+
270
+ def test_delete_does_not_write_column_of_destroyed_model
271
+ model = model_with_column(IDENTIFIER)
272
+ model.save!
273
+
274
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
275
+ ActiveRecord::Base.transaction do
276
+ model.destroy!
277
+ end
278
+ assert model.destroyed?
279
+ assert_equal [IMAGE_ID], fake.deleted_ids
280
+
281
+ # destroy 済み (frozen) のモデルに対して delete しても FrozenError にならない
282
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
283
+ file.delete
284
+ end
285
+ end
286
+
287
+ # ============================================================
288
+ # store の詳細な挙動 (Resizing.post を差し替えて送信内容を検証)
289
+ # ============================================================
290
+
291
+ POST_RESPONSE = {
292
+ 'id' => IMAGE_ID,
293
+ 'public_id' => IDENTIFIER,
294
+ 'content_type' => 'image/jpeg'
295
+ }.freeze
296
+
297
+ def capture_post(response = POST_RESPONSE, &block)
298
+ captured = {}
299
+ responder = lambda do |content, options|
300
+ captured[:content] = content
301
+ captured[:options] = options
302
+ response.dup
303
+ end
304
+ Resizing.stub(:post, responder, &block)
305
+ captured
306
+ end
307
+
308
+ def new_storage_file(model = TestModel.new)
309
+ Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
310
+ end
311
+
312
+ def test_store_posts_uploaded_file_with_its_content_type_and_original_filename
313
+ file = new_storage_file
314
+ uploaded_file = ActionDispatch::Http::UploadedFile.new(
315
+ filename: 'my photo.jpg',
316
+ type: 'image/jpeg',
317
+ tempfile: ::File.open('test/data/images/sample1.jpg', 'r')
318
+ )
319
+
320
+ captured = capture_post { file.store(uploaded_file) }
321
+
322
+ assert_equal 'image/jpeg', captured[:options][:content_type]
323
+ assert_equal 'my photo.jpg', captured[:options][:filename]
324
+ assert captured[:content].respond_to?(:read)
325
+ assert_equal 0, captured[:content].pos, 'IO should be rewound before upload'
326
+ end
327
+
328
+ def test_store_guesses_content_type_from_extension_for_plain_file
329
+ file = new_storage_file
330
+ source_file = ::File.open('test/data/images/sample1.jpg', 'r')
331
+ source_file.read(10) # 読み進めた状態でも巻き戻して送る
332
+
333
+ captured = capture_post { file.store(source_file) }
334
+
335
+ assert_equal 'image/jpeg', captured[:options][:content_type]
336
+ assert_equal 'sample1.jpg', captured[:options][:filename]
337
+ assert_equal 0, captured[:content].pos
338
+ end
339
+
340
+ # Issue #88: MIME::Types に登録のない拡張子でも例外にならず、
341
+ # application/octet-stream にフォールバックすること
342
+ def test_store_falls_back_to_octet_stream_for_unknown_extension
343
+ # 前提: この拡張子は MIME::Types に登録されていない
344
+ assert_empty MIME::Types.type_for('bookmark.url')
345
+
346
+ file = new_storage_file
347
+ tempfile = Tempfile.new(['bookmark', '.url'])
348
+ begin
349
+ tempfile.write("[InternetShortcut]\nURL=https://example.com/\n")
350
+ tempfile.rewind
351
+
352
+ captured = capture_post { file.store(tempfile) }
353
+
354
+ assert_equal 'application/octet-stream', captured[:options][:content_type]
355
+ assert_equal ::File.basename(tempfile.path), captured[:options][:filename]
356
+ ensure
357
+ tempfile.close!
358
+ end
359
+ end
360
+
361
+ def test_guess_content_type_falls_back_for_unknown_or_missing_path
362
+ file = new_storage_file
363
+
364
+ assert_equal 'image/jpeg', file.send(:guess_content_type, 'sample1.jpg')
365
+ assert_equal 'application/octet-stream', file.send(:guess_content_type, 'bookmark.url')
366
+ assert_equal 'application/octet-stream', file.send(:guess_content_type, 'no_extension')
367
+ assert_equal 'application/octet-stream', file.send(:guess_content_type, nil)
368
+ end
369
+
370
+ def test_store_sends_basename_only_as_filename
371
+ file = new_storage_file
372
+ uploaded_file = ActionDispatch::Http::UploadedFile.new(
373
+ filename: '/some/dir/photo.jpg',
374
+ type: 'image/jpeg',
375
+ tempfile: ::File.open('test/data/images/sample1.jpg', 'r')
376
+ )
377
+
378
+ captured = capture_post { file.store(uploaded_file) }
379
+
380
+ assert_equal 'photo.jpg', captured[:options][:filename]
381
+ end
382
+
383
+ def test_store_writes_public_id_into_model_column
384
+ model = TestModel.new
385
+ file = new_storage_file(model)
386
+
387
+ capture_post { file.store(::File.open('test/data/images/sample1.jpg', 'r')) }
388
+
389
+ assert_equal IDENTIFIER, model.read_attribute(:resizing_picture)
390
+ assert_equal IDENTIFIER, file.public_id.to_s
391
+ assert_equal IDENTIFIER, file.current_path
392
+ assert_equal IMAGE_ID, file.public_id.image_id
393
+ end
394
+
395
+ def test_store_uses_content_type_from_response
396
+ file = new_storage_file
397
+ response = POST_RESPONSE.merge('content_type' => 'image/webp')
398
+
399
+ capture_post(response) { file.store(::File.open('test/data/images/sample1.jpg', 'r')) }
400
+
401
+ assert_equal 'image/webp', file.content_type
402
+ end
403
+
404
+ def test_store_returns_true
405
+ file = new_storage_file
406
+ result = nil
407
+
408
+ capture_post { result = file.store(::File.open('test/data/images/sample1.jpg', 'r')) }
409
+
410
+ assert_equal true, result
411
+ end
412
+
413
+ def test_store_raises_for_storage_file_instance
414
+ model = TestModel.new
415
+ file = new_storage_file(model)
416
+ other = new_storage_file(model)
417
+
418
+ assert_raises(NotImplementedError) { file.store(other) }
419
+ end
420
+
421
+ # ============================================================
422
+ # current_path / name / public_id
423
+ # ============================================================
424
+
425
+ def test_current_path_falls_back_to_model_column
426
+ model = model_with_column(IDENTIFIER)
427
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
428
+
429
+ assert_equal IDENTIFIER, file.current_path
430
+ assert_equal IDENTIFIER, file.path
431
+ end
432
+
433
+ def test_current_path_prefers_identifier_over_model_column
434
+ model = model_with_column(OTHER_IDENTIFIER)
435
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
436
+
437
+ assert_equal IDENTIFIER, file.current_path
438
+ end
439
+
440
+ def test_name_reads_from_model_column_not_identifier
441
+ model = model_with_column(OTHER_IDENTIFIER)
442
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
443
+
444
+ assert_equal 'new-image-id-2222-2222-222222222222', file.name
445
+ end
446
+
447
+ def test_public_id_exposes_parsed_parts
448
+ model = TestModel.new
449
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
450
+
451
+ assert_equal IMAGE_ID, file.public_id.image_id
452
+ assert_equal 'e06e710d-f026-4dcf-b2c0-eab0de8bb83f', file.public_id.project_id
453
+ assert_equal '_8c5lEhDB5RT3PZp1Fn5PYGm9YVx_x0e', file.public_id.version
454
+ end
455
+
456
+ def test_retrieve_replaces_public_id
457
+ model = TestModel.new
458
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
459
+
460
+ file.retrieve(OTHER_IDENTIFIER)
461
+
462
+ assert_equal OTHER_IDENTIFIER, file.public_id.to_s
463
+ assert_equal OTHER_IDENTIFIER, file.current_path
464
+ end
465
+
466
+ # ============================================================
467
+ # Issue #91: 未定義の `file` を参照していたメソッド群
468
+ # (size / content_type / read / exists? / attributes)
469
+ # ============================================================
470
+
471
+ # test/vcr/client/metadata.yml のカセットに対応する identifier
472
+ METADATA_IDENTIFIER = '/projects/e06e710d-f026-4dcf-b2c0-eab0de8bb83f/upload/images/87263920-2081-498e-a107-9625f4fde01b/vHg9VFvdI6HRzLFbV495VdwVmHIspLRCo'
473
+ METADATA_SIZE = 848_590
474
+
475
+ def storage_file_for(identifier)
476
+ Resizing::CarrierWave::Storage::File.new(TestModel.new.resizing_picture, identifier)
477
+ end
478
+
479
+ def test_size_content_type_exists_and_attributes_come_from_metadata_api
480
+ file = storage_file_for(METADATA_IDENTIFIER)
481
+
482
+ # メタデータは1回だけ取得され、以降はメモ化される
483
+ assert_vcr_requests_made 'client/metadata' do
484
+ assert_equal METADATA_SIZE, file.size
485
+ assert_equal 'image/jpeg', file.content_type
486
+ assert file.exists?
487
+ assert_equal 'sample1.jpg', file.attributes['filename']
488
+ end
489
+ end
490
+
491
+ def test_metadata_backed_methods_do_not_raise_name_error_without_public_id
492
+ file = new_storage_file
493
+
494
+ # public_id がないのでリクエストは発行されず、既定値を返す
495
+ assert_vcr_no_requests 'client/metadata' do
496
+ assert_equal 0, file.size
497
+ assert_nil file.content_type
498
+ refute file.exists?
499
+ assert_nil file.attributes
500
+ end
501
+ end
502
+
503
+ def test_metadata_backed_methods_do_not_raise_when_api_fails
504
+ file = storage_file_for(IDENTIFIER)
505
+
506
+ Resizing.stub(:metadata, ->(*) { raise Resizing::APIError, 'boom' }) do
507
+ assert_equal 0, file.size
508
+ assert_nil file.content_type
509
+ refute file.exists?
510
+ assert_nil file.attributes
511
+ end
512
+ end
513
+
514
+ def test_metadata_not_found_response_is_treated_as_missing
515
+ file = storage_file_for(IDENTIFIER)
516
+ not_found = { 'error' => 'ActiveRecord::RecordNotFound' }
517
+
518
+ Resizing.stub(:metadata, ->(*) { not_found }) do
519
+ refute file.exists?
520
+ assert_equal 0, file.size
521
+ assert_nil file.content_type
522
+ end
523
+ end
524
+
525
+ def test_content_type_prefers_locally_known_value_over_metadata_api
526
+ file = new_storage_file
527
+
528
+ # store 済みで content_type が分かっている場合はメタデータを取りに行かない
529
+ assert_vcr_no_requests 'client/metadata' do
530
+ capture_post { file.store(::File.open('test/data/images/sample1.jpg', 'r')) }
531
+
532
+ assert_equal 'image/jpeg', file.content_type
533
+ end
534
+ end
535
+
536
+ def test_metadata_falls_back_to_model_column_when_built_without_identifier
537
+ model = model_with_column(METADATA_IDENTIFIER)
538
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
539
+
540
+ assert_vcr_requests_made 'client/metadata' do
541
+ assert_equal METADATA_SIZE, file.size
542
+ end
543
+ end
544
+
545
+ def test_retrieve_drops_cached_metadata_only_when_identifier_changes
546
+ file = storage_file_for(METADATA_IDENTIFIER)
547
+
548
+ assert_vcr_requests_made 'client/metadata' do
549
+ assert_equal METADATA_SIZE, file.size
550
+ # 同じ identifier での retrieve ではメタデータを再取得しない
551
+ file.retrieve(METADATA_IDENTIFIER)
552
+ assert_equal METADATA_SIZE, file.size
553
+ end
554
+
555
+ file.retrieve(IDENTIFIER)
556
+ Resizing.stub(:metadata, ->(*) { { 'size' => 1 } }) do
557
+ assert_equal 1, file.size
558
+ end
559
+ end
560
+
561
+ def test_read_raises_not_implemented_error_instead_of_name_error
562
+ file = storage_file_for(METADATA_IDENTIFIER)
563
+
564
+ error = assert_raises(NotImplementedError) { file.read }
565
+ assert_match(/Resizing/, error.message)
566
+ end
567
+
568
+ # Issue #91 の再現手順: DB から読み直したモデルの size が NameError にならないこと
569
+ # (CarrierWave の Uploader::Proxy#size は file.try(:size) を呼ぶ)
570
+ def test_uploader_proxy_size_and_content_type_for_model_loaded_from_db
571
+ model = model_with_column(METADATA_IDENTIFIER)
572
+ model.save!
573
+ loaded = TestModel.find(model.id)
574
+
575
+ assert_vcr_requests_made 'client/metadata' do
576
+ assert_equal METADATA_SIZE, loaded.resizing_picture.size
577
+ assert_equal 'image/jpeg', loaded.resizing_picture.content_type
578
+ end
579
+ end
580
+
581
+ # Issue #94: カラムに空文字が入っているレコードでも delete で例外にならない
582
+ def test_delete_does_nothing_when_column_is_empty_string
583
+ model = model_with_column('')
584
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture)
585
+
586
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
587
+ assert_nil file.delete
588
+ assert_empty fake.deleted_ids
589
+ end
590
+
591
+ assert_equal '', model.read_attribute(:resizing_picture)
592
+ end
593
+
594
+ def test_delete_does_nothing_when_identifier_is_empty_string
595
+ model = model_with_column('')
596
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, '')
597
+
598
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
599
+ assert_nil file.delete
600
+ assert_empty fake.deleted_ids
601
+ end
602
+ end
603
+
604
+ def test_delete_with_valid_public_id_clears_model_column
605
+ VCR.use_cassette 'carrier_wave_test/remove_resizing_picture', record: :none do
606
+ model = model_with_column(IDENTIFIER)
607
+ file = Resizing::CarrierWave::Storage::File.new(model.resizing_picture, IDENTIFIER)
608
+
609
+ file.delete
610
+
611
+ assert_nil model.read_attribute(:resizing_picture)
612
+ end
613
+ end
168
614
  end
169
615
  end
170
616
  end
@@ -6,16 +6,11 @@ module Resizing
6
6
  module CarrierWave
7
7
  module Storage
8
8
  class RemoteTest < Minitest::Test
9
+ include FakeApiClientAssertions
10
+ include ResizingTestConfiguration
11
+
9
12
  def setup
10
- @configuration_template = {
11
- image_host: 'http://192.168.56.101:5000',
12
- video_host: 'http://192.168.56.101:5000',
13
- project_id: 'e06e710d-f026-4dcf-b2c0-eab0de8bb83f',
14
- secret_token: 'ewbym2r1pk49x1d2lxdbiiavnqp25j2kh00hsg3koy0ppm620x5mhlmgl3rq5ci8',
15
- open_timeout: 10,
16
- response_timeout: 20
17
- }
18
- Resizing.configure = @configuration_template
13
+ configure_resizing
19
14
 
20
15
  model = TestModel.new
21
16
  @uploader = model.resizing_picture
@@ -69,6 +64,93 @@ module Resizing
69
64
  assert_instance_of Resizing::CarrierWave::Storage::File, result
70
65
  assert_equal identifier, result.public_id.to_s
71
66
  end
67
+
68
+ IDENTIFIER = '/projects/e06e710d-f026-4dcf-b2c0-eab0de8bb83f/upload/images/14ea7aac-a194-4330-931f-6b562aec413d/v_8c5lEhDB5RT3PZp1Fn5PYGm9YVx_x0e'
69
+
70
+ def test_store_uploads_and_returns_file_with_public_id
71
+ VCR.use_cassette 'carrier_wave_test/save', record: :none do
72
+ file = @storage.store!(::File.open('test/data/images/sample1.jpg', 'r'))
73
+
74
+ assert_instance_of Resizing::CarrierWave::Storage::File, file
75
+ assert_equal IDENTIFIER, file.public_id.to_s
76
+ assert_equal 'image/jpeg', file.content_type
77
+ end
78
+
79
+ assert_equal IDENTIFIER, @uploader.model.read_attribute(:resizing_picture)
80
+ end
81
+
82
+ def test_cache_uploads_immediately_like_store
83
+ # Resizing はキャッシュをサポートしないため cache! でも直接アップロードする
84
+ VCR.use_cassette 'carrier_wave_test/save', record: :none do
85
+ file = @storage.cache!(::File.open('test/data/images/sample1.jpg', 'r'))
86
+
87
+ assert_instance_of Resizing::CarrierWave::Storage::File, file
88
+ assert_equal IDENTIFIER, file.public_id.to_s
89
+ end
90
+
91
+ assert_equal IDENTIFIER, @uploader.model.read_attribute(:resizing_picture)
92
+ end
93
+
94
+ def test_retrieve_returns_new_file_instance_each_time
95
+ first = @storage.retrieve!(IDENTIFIER)
96
+ second = @storage.retrieve!(IDENTIFIER)
97
+
98
+ refute_same first, second
99
+ assert_equal first.public_id.to_s, second.public_id.to_s
100
+ end
101
+
102
+ IMAGE_ID = '14ea7aac-a194-4330-931f-6b562aec413d'
103
+ OTHER_IDENTIFIER = '/projects/e06e710d-f026-4dcf-b2c0-eab0de8bb83f/upload/images/new-image-id-2222-2222-222222222222/v2'
104
+
105
+ def test_remove_deletes_the_image_stored_in_the_model_column
106
+ model = @uploader.model
107
+ model.send(:write_attribute, :resizing_picture, IDENTIFIER)
108
+
109
+ file = with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
110
+ result = @storage.remove!(nil)
111
+ assert_equal [IMAGE_ID], fake.deleted_ids
112
+ result
113
+ end
114
+
115
+ assert_instance_of Resizing::CarrierWave::Storage::File, file
116
+ assert_nil model.read_attribute(:resizing_picture)
117
+ end
118
+
119
+ def test_remove_accepts_a_carrier_wave_file_argument
120
+ # CarrierWave が storage.remove!(file) 経由で呼ぶ場合も ArgumentError にならないこと
121
+ model = @uploader.model
122
+ model.send(:write_attribute, :resizing_picture, IDENTIFIER)
123
+
124
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
125
+ file = @uploader.file
126
+ result = @storage.remove!(file)
127
+
128
+ assert_equal [IMAGE_ID], fake.deleted_ids
129
+ assert_same file, result
130
+ end
131
+
132
+ assert_nil model.read_attribute(:resizing_picture)
133
+ end
134
+
135
+ def test_remove_deletes_the_given_file_not_the_current_column_value
136
+ # 画像更新後に古い画像を消す場合: 削除対象は渡された file、カラムは新しい画像のまま
137
+ model = @uploader.model
138
+ model.send(:write_attribute, :resizing_picture, OTHER_IDENTIFIER)
139
+ file = Resizing::CarrierWave::Storage::File.new(@uploader, IDENTIFIER)
140
+
141
+ with_fake_api_client({ 'id' => IMAGE_ID }) do |fake|
142
+ @storage.remove!(file)
143
+
144
+ assert_equal [IMAGE_ID], fake.deleted_ids
145
+ end
146
+
147
+ assert_equal OTHER_IDENTIFIER, model.read_attribute(:resizing_picture)
148
+ end
149
+
150
+ def test_storage_is_subclass_of_carrierwave_abstract_storage
151
+ assert Remote < ::CarrierWave::Storage::Abstract
152
+ assert_same @uploader, @storage.uploader
153
+ end
72
154
  end
73
155
  end
74
156
  end