middleman-s3_sync 4.6.1 → 4.6.3

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.
@@ -0,0 +1,525 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'AWS SDK Parameter Validation' do
4
+ let(:options) { Middleman::S3Sync::Options.new }
5
+ let(:s3_client) { instance_double(Aws::S3::Client) }
6
+ let(:s3_resource) { instance_double(Aws::S3::Resource) }
7
+ let(:bucket) { instance_double(Aws::S3::Bucket) }
8
+ let(:s3_object) { instance_double(Aws::S3::Object) }
9
+
10
+ before do
11
+ Middleman::S3Sync.s3_sync_options = options
12
+ options.build_dir = "build"
13
+ options.bucket = "test-bucket"
14
+ options.acl = "public-read"
15
+ options.index_document = "index.html"
16
+ options.error_document = "404.html"
17
+ options.version_bucket = true
18
+
19
+ allow(Aws::S3::Client).to receive(:new).and_return(s3_client)
20
+ allow(Aws::S3::Resource).to receive(:new).and_return(s3_resource)
21
+ allow(s3_resource).to receive(:bucket).and_return(bucket)
22
+ allow(bucket).to receive(:exists?).and_return(true)
23
+ allow(bucket).to receive(:object).and_return(s3_object)
24
+ allow(s3_object).to receive(:put).and_return(true)
25
+
26
+ # Allow Middleman::S3Sync to use our mocked client/bucket
27
+ allow(Middleman::S3Sync).to receive(:s3_client).and_return(s3_client)
28
+ allow(Middleman::S3Sync).to receive(:bucket).and_return(bucket)
29
+ allow(Middleman::S3Sync).to receive(:say_status)
30
+ end
31
+
32
+ describe 'put_bucket_website parameters' do
33
+ it 'uses symbol keys for index_document and error_document' do
34
+ expect(s3_client).to receive(:put_bucket_website) do |params|
35
+ expect(params[:bucket]).to eq("test-bucket")
36
+ expect(params[:website_configuration]).to have_key(:index_document)
37
+ expect(params[:website_configuration]).to have_key(:error_document)
38
+
39
+ # Verify the nested structure uses symbols, not strings
40
+ expect(params[:website_configuration][:index_document]).to have_key(:suffix)
41
+ expect(params[:website_configuration][:error_document]).to have_key(:key)
42
+
43
+ # Verify the values are correct
44
+ expect(params[:website_configuration][:index_document][:suffix]).to eq("index.html")
45
+ expect(params[:website_configuration][:error_document][:key]).to eq("404.html")
46
+ end
47
+
48
+ Middleman::S3Sync.send(:update_bucket_website)
49
+ end
50
+
51
+ context 'when only index_document is set' do
52
+ before do
53
+ options.error_document = nil
54
+ end
55
+
56
+ it 'only includes index_document in website configuration' do
57
+ expect(s3_client).to receive(:put_bucket_website) do |params|
58
+ expect(params[:website_configuration]).to have_key(:index_document)
59
+ expect(params[:website_configuration]).not_to have_key(:error_document)
60
+ end
61
+
62
+ Middleman::S3Sync.send(:update_bucket_website)
63
+ end
64
+ end
65
+
66
+ context 'when neither document is set' do
67
+ before do
68
+ options.index_document = nil
69
+ options.error_document = nil
70
+ end
71
+
72
+ it 'does not call put_bucket_website' do
73
+ expect(s3_client).not_to receive(:put_bucket_website)
74
+
75
+ Middleman::S3Sync.send(:update_bucket_website)
76
+ end
77
+ end
78
+
79
+ context 'when only error_document is set' do
80
+ before do
81
+ options.index_document = nil
82
+ end
83
+
84
+ it 'raises an error because S3 requires index_document if error_document is specified' do
85
+ expect {
86
+ Middleman::S3Sync.send(:update_bucket_website)
87
+ }.to raise_error('S3 requires `index_document` if `error_document` is specified')
88
+ end
89
+ end
90
+ end
91
+
92
+ describe 'put_bucket_versioning parameters' do
93
+ it 'uses correct parameter structure' do
94
+ expect(s3_client).to receive(:put_bucket_versioning) do |params|
95
+ expect(params[:bucket]).to eq("test-bucket")
96
+ expect(params[:versioning_configuration]).to be_a(Hash)
97
+ expect(params[:versioning_configuration][:status]).to eq("Enabled")
98
+ end
99
+
100
+ Middleman::S3Sync.send(:update_bucket_versioning)
101
+ end
102
+
103
+ context 'when version_bucket is false' do
104
+ before do
105
+ options.version_bucket = false
106
+ end
107
+
108
+ it 'does not call put_bucket_versioning' do
109
+ expect(s3_client).not_to receive(:put_bucket_versioning)
110
+
111
+ Middleman::S3Sync.send(:update_bucket_versioning)
112
+ end
113
+ end
114
+ end
115
+
116
+ describe 'S3 object upload parameters' do
117
+ let(:mm_resource) do
118
+ double(
119
+ destination_path: 'test/file.html',
120
+ content_type: 'text/html'
121
+ )
122
+ end
123
+
124
+ let(:resource) { Middleman::S3Sync::Resource.new(mm_resource, nil) }
125
+
126
+ before do
127
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
128
+ allow(File).to receive(:exist?).with('build/test/file.html.gz').and_return(false)
129
+ allow(File).to receive(:read).with('build/test/file.html').and_return('test content')
130
+ allow(File).to receive(:directory?).with('build/test/file.html').and_return(false)
131
+ allow(s3_object).to receive(:head).and_return(nil)
132
+ options.dry_run = false
133
+ end
134
+
135
+ it 'uses correct metadata key format' do
136
+ expect(s3_object).to receive(:put) do |upload_options|
137
+ # Verify basic parameters
138
+ expect(upload_options[:body]).to eq('test content')
139
+ expect(upload_options[:content_type]).to eq('text/html')
140
+ expect(upload_options[:acl]).to eq('public-read')
141
+
142
+ # Verify metadata uses correct key format (suffix only, not full header name)
143
+ expect(upload_options[:metadata]).to be_a(Hash)
144
+ expect(upload_options[:metadata]).to have_key('content-md5')
145
+ expect(upload_options[:metadata]).not_to have_key('x-amz-meta-content-md5')
146
+
147
+ # Verify metadata value is the MD5 hash
148
+ expected_md5 = Digest::MD5.hexdigest('test content')
149
+ expect(upload_options[:metadata]['content-md5']).to eq(expected_md5)
150
+ end
151
+
152
+ resource.upload!
153
+ end
154
+
155
+ context 'when ACL is set to empty string (for buckets with ACLs disabled)' do
156
+ before do
157
+ options.acl = ''
158
+ end
159
+
160
+ it 'does not include acl parameter in upload' do
161
+ expect(s3_object).to receive(:put) do |upload_options|
162
+ expect(upload_options).not_to have_key(:acl)
163
+ expect(upload_options[:body]).to eq('test content')
164
+ expect(upload_options[:content_type]).to eq('text/html')
165
+ end
166
+
167
+ resource.upload!
168
+ end
169
+ end
170
+
171
+ context 'when ACL is set to nil (for buckets with ACLs disabled)' do
172
+ before do
173
+ options.acl = nil
174
+ end
175
+
176
+ it 'does not include acl parameter in upload' do
177
+ expect(s3_object).to receive(:put) do |upload_options|
178
+ expect(upload_options).not_to have_key(:acl)
179
+ expect(upload_options[:body]).to eq('test content')
180
+ expect(upload_options[:content_type]).to eq('text/html')
181
+ end
182
+
183
+ resource.upload!
184
+ end
185
+ end
186
+
187
+ context 'when bucket does not support ACLs (auto-detection)' do
188
+ before do
189
+ # ACL is enabled by default
190
+ expect(options.acl).to eq('public-read')
191
+ end
192
+
193
+ it 'automatically retries without ACL when AccessControlListNotSupported error occurs' do
194
+ call_count = 0
195
+ expect(s3_object).to receive(:put).twice do |upload_options|
196
+ call_count += 1
197
+ if call_count == 1
198
+ # First call should include ACL
199
+ expect(upload_options[:acl]).to eq('public-read')
200
+ raise Aws::S3::Errors::AccessControlListNotSupported.new(nil, 'The bucket does not allow ACLs')
201
+ else
202
+ # Second call should not include ACL
203
+ expect(upload_options).not_to have_key(:acl)
204
+ expect(upload_options[:body]).to eq('test content')
205
+ expect(upload_options[:content_type]).to eq('text/html')
206
+ end
207
+ end
208
+
209
+ # Should automatically disable ACLs after the error
210
+ resource.upload!
211
+ expect(options.acl_enabled?).to be false
212
+ end
213
+
214
+ it 'permanently disables ACLs after detecting bucket does not support them' do
215
+ call_count = 0
216
+ allow(s3_object).to receive(:put) do |upload_options|
217
+ call_count += 1
218
+ if call_count == 1
219
+ expect(upload_options[:acl]).to eq('public-read')
220
+ raise Aws::S3::Errors::AccessControlListNotSupported.new(nil, 'The bucket does not allow ACLs')
221
+ else
222
+ # Second call should succeed without ACL
223
+ expect(upload_options).not_to have_key(:acl)
224
+ true
225
+ end
226
+ end
227
+
228
+ resource.upload!
229
+ expect(options.acl_enabled?).to be false
230
+
231
+ # Verify ACLs stay disabled for future uploads
232
+ resource.upload!
233
+ expect(call_count).to eq(3) # First attempt, retry, and third upload
234
+ end
235
+ end
236
+
237
+ context 'when gzip is enabled' do
238
+ before do
239
+ options.prefer_gzip = true
240
+ allow(File).to receive(:exist?).with('build/test/file.html.gz').and_return(true)
241
+ allow(File).to receive(:read).with('build/test/file.html.gz').and_return('gzipped content')
242
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
243
+ allow(File).to receive(:read).with('build/test/file.html').and_return('original content')
244
+
245
+ # Mock the HEAD response to avoid calling it during redirect?
246
+ head_response = double(
247
+ metadata: {},
248
+ etag: '"abc123"',
249
+ content_encoding: nil,
250
+ cache_control: nil,
251
+ website_redirect_location: nil
252
+ )
253
+ allow(s3_object).to receive(:head).and_return(head_response)
254
+ resource.instance_variable_set(:@full_s3_resource, head_response)
255
+ end
256
+
257
+ it 'includes content_encoding parameter' do
258
+ expect(s3_object).to receive(:put) do |upload_options|
259
+ expect(upload_options[:content_encoding]).to eq('gzip')
260
+ end
261
+
262
+ resource.upload!
263
+ end
264
+ end
265
+
266
+ context 'when reduced redundancy storage is enabled' do
267
+ before do
268
+ options.reduced_redundancy_storage = true
269
+ end
270
+
271
+ it 'includes storage_class parameter' do
272
+ expect(s3_object).to receive(:put) do |upload_options|
273
+ expect(upload_options[:storage_class]).to eq('REDUCED_REDUNDANCY')
274
+ end
275
+
276
+ resource.upload!
277
+ end
278
+ end
279
+
280
+ context 'when encryption is enabled' do
281
+ before do
282
+ options.encryption = true
283
+ end
284
+
285
+ it 'includes server_side_encryption parameter' do
286
+ expect(s3_object).to receive(:put) do |upload_options|
287
+ expect(upload_options[:server_side_encryption]).to eq('AES256')
288
+ end
289
+
290
+ resource.upload!
291
+ end
292
+ end
293
+
294
+ context 'when resource has a redirect' do
295
+ let(:mm_resource) do
296
+ double(
297
+ destination_path: 'redirect/file.html',
298
+ content_type: 'text/html',
299
+ redirect?: true,
300
+ target_url: 'https://example.com/new-location'
301
+ )
302
+ end
303
+
304
+ before do
305
+ allow(File).to receive(:exist?).with('build/redirect/file.html').and_return(true)
306
+ allow(File).to receive(:exist?).with('build/redirect/file.html.gz').and_return(false)
307
+ allow(File).to receive(:read).with('build/redirect/file.html').and_return('redirect content')
308
+ allow(File).to receive(:directory?).with('build/redirect/file.html').and_return(false)
309
+ allow(s3_object).to receive(:head).and_return(nil)
310
+ allow(resource).to receive(:redirect?).and_return(true)
311
+ allow(resource).to receive(:redirect_url).and_return('https://example.com/new-location')
312
+ end
313
+
314
+ it 'includes website_redirect_location parameter' do
315
+ expect(s3_object).to receive(:put) do |upload_options|
316
+ expect(upload_options[:website_redirect_location]).to eq('https://example.com/new-location')
317
+ end
318
+
319
+ resource.upload!
320
+ end
321
+ end
322
+ end
323
+
324
+ describe 'S3 object metadata retrieval' do
325
+ let(:mm_resource) do
326
+ double(
327
+ destination_path: 'test/file.html',
328
+ content_type: 'text/html'
329
+ )
330
+ end
331
+
332
+ let(:resource) { Middleman::S3Sync::Resource.new(mm_resource, nil) }
333
+ let(:head_response) do
334
+ double(
335
+ metadata: { 'content-md5' => 'abc123def456' },
336
+ etag: '"def456abc123"',
337
+ content_encoding: nil,
338
+ cache_control: nil,
339
+ website_redirect_location: nil
340
+ )
341
+ end
342
+
343
+ before do
344
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
345
+ allow(File).to receive(:read).with('build/test/file.html').and_return('test content')
346
+ allow(File).to receive(:directory?).with('build/test/file.html').and_return(false)
347
+ allow(s3_object).to receive(:head).and_return(head_response)
348
+ resource.instance_variable_set(:@full_s3_resource, head_response)
349
+ end
350
+
351
+ it 'reads metadata using correct key format' do
352
+ expect(resource.remote_content_md5).to eq('abc123def456')
353
+ end
354
+
355
+ it 'does not try to read metadata with old header format' do
356
+ # Ensure it's not looking for the full header name
357
+ expect(head_response.metadata).not_to receive(:[]).with('x-amz-meta-content-md5')
358
+
359
+ resource.remote_content_md5
360
+ end
361
+ end
362
+
363
+ describe 'to_h method for legacy compatibility' do
364
+ let(:mm_resource) do
365
+ double(
366
+ destination_path: 'test/file.html',
367
+ content_type: 'text/html'
368
+ )
369
+ end
370
+
371
+ let(:resource) { Middleman::S3Sync::Resource.new(mm_resource, nil) }
372
+
373
+ before do
374
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
375
+ allow(File).to receive(:exist?).with('build/test/file.html.gz').and_return(false)
376
+ allow(File).to receive(:read).with('build/test/file.html').and_return('test content')
377
+ allow(File).to receive(:directory?).with('build/test/file.html').and_return(false)
378
+ allow(s3_object).to receive(:head).and_return(nil)
379
+ end
380
+
381
+ it 'returns attributes with correct key formats' do
382
+ attributes = resource.to_h
383
+
384
+ expect(attributes[:key]).to eq('test/file.html')
385
+ expect(attributes[:acl]).to eq('public-read')
386
+ expect(attributes[:content_type]).to eq('text/html')
387
+ expect(attributes['content-md5']).to be_a(String)
388
+ expect(attributes).not_to have_key('x-amz-meta-content-md5')
389
+ end
390
+
391
+ context 'when ACL is set to empty string' do
392
+ before do
393
+ options.acl = ''
394
+ end
395
+
396
+ it 'does not include acl in attributes' do
397
+ attributes = resource.to_h
398
+
399
+ expect(attributes).not_to have_key(:acl)
400
+ expect(attributes[:key]).to eq('test/file.html')
401
+ expect(attributes[:content_type]).to eq('text/html')
402
+ end
403
+ end
404
+
405
+ context 'when ACL is set to nil' do
406
+ before do
407
+ options.acl = nil
408
+ end
409
+
410
+ it 'does not include acl in attributes' do
411
+ attributes = resource.to_h
412
+
413
+ expect(attributes).not_to have_key(:acl)
414
+ expect(attributes[:key]).to eq('test/file.html')
415
+ expect(attributes[:content_type]).to eq('text/html')
416
+ end
417
+ end
418
+
419
+ context 'when resource has a redirect' do
420
+ let(:mm_resource) do
421
+ double(
422
+ destination_path: 'redirect/file.html',
423
+ content_type: 'text/html',
424
+ redirect?: true,
425
+ target_url: 'https://example.com/new-location'
426
+ )
427
+ end
428
+
429
+ before do
430
+ allow(File).to receive(:exist?).with('build/redirect/file.html').and_return(true)
431
+ allow(File).to receive(:exist?).with('build/redirect/file.html.gz').and_return(false)
432
+ allow(File).to receive(:read).with('build/redirect/file.html').and_return('redirect content')
433
+ allow(File).to receive(:directory?).with('build/redirect/file.html').and_return(false)
434
+ allow(s3_object).to receive(:head).and_return(nil)
435
+ allow(resource).to receive(:redirect?).and_return(true)
436
+ allow(resource).to receive(:redirect_url).and_return('https://example.com/new-location')
437
+ end
438
+
439
+ it 'includes redirect with correct key format' do
440
+ attributes = resource.to_h
441
+
442
+ expect(attributes['website-redirect-location']).to eq('https://example.com/new-location')
443
+ expect(attributes).not_to have_key('x-amz-website-redirect-location')
444
+ end
445
+ end
446
+ end
447
+
448
+ describe 'Regression tests for Fog-style parameter issues' do
449
+ # These tests validate that we've fixed the old Fog-style parameter formatting
450
+ # and demonstrate what would fail if we reverted to the old style
451
+
452
+ it 'does not use string keys for website configuration (old Fog style)' do
453
+ # This would fail if we reverted to the old format:
454
+ # opts[:index_document] = { "suffix" => s3_sync_options.index_document }
455
+
456
+ expect(s3_client).to receive(:put_bucket_website) do |params|
457
+ config = params[:website_configuration]
458
+
459
+ # Ensure we're not using string keys (old Fog style)
460
+ expect(config[:index_document]).not_to have_key("suffix")
461
+ expect(config[:error_document]).not_to have_key("key")
462
+
463
+ # Ensure we ARE using symbol keys (correct AWS SDK style)
464
+ expect(config[:index_document]).to have_key(:suffix)
465
+ expect(config[:error_document]).to have_key(:key)
466
+ end
467
+
468
+ Middleman::S3Sync.send(:update_bucket_website)
469
+ end
470
+
471
+ it 'does not use full header names in metadata (old style)' do
472
+ mm_resource = double(
473
+ destination_path: 'test/file.html',
474
+ content_type: 'text/html'
475
+ )
476
+ resource = Middleman::S3Sync::Resource.new(mm_resource, nil)
477
+
478
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
479
+ allow(File).to receive(:exist?).with('build/test/file.html.gz').and_return(false)
480
+ allow(File).to receive(:read).with('build/test/file.html').and_return('test content')
481
+ allow(File).to receive(:directory?).with('build/test/file.html').and_return(false)
482
+ allow(s3_object).to receive(:head).and_return(nil)
483
+ options.dry_run = false
484
+
485
+ expect(s3_object).to receive(:put) do |upload_options|
486
+ # Ensure we're not using the old full header format
487
+ expect(upload_options[:metadata]).not_to have_key('x-amz-meta-content-md5')
488
+
489
+ # Ensure we ARE using the correct suffix-only format
490
+ expect(upload_options[:metadata]).to have_key('content-md5')
491
+ end
492
+
493
+ resource.upload!
494
+ end
495
+
496
+ it 'validates that old constants are no longer used' do
497
+ # This test ensures the old constants were removed/changed
498
+ # If they still existed, this would be a sign we didn't clean up properly
499
+
500
+ mm_resource = double(
501
+ destination_path: 'test/file.html',
502
+ content_type: 'text/html'
503
+ )
504
+ resource = Middleman::S3Sync::Resource.new(mm_resource, nil)
505
+
506
+ allow(File).to receive(:exist?).with('build/test/file.html').and_return(true)
507
+ allow(File).to receive(:exist?).with('build/test/file.html.gz').and_return(false)
508
+ allow(File).to receive(:read).with('build/test/file.html').and_return('test content')
509
+ allow(File).to receive(:directory?).with('build/test/file.html').and_return(false)
510
+ allow(s3_object).to receive(:head).and_return(nil)
511
+ allow(resource).to receive(:redirect?).and_return(true)
512
+ allow(resource).to receive(:redirect_url).and_return('https://example.com/redirect')
513
+
514
+ attributes = resource.to_h
515
+
516
+ # Validate that the old constant values are not used
517
+ expect(attributes).not_to have_key('x-amz-meta-content-md5')
518
+ expect(attributes).not_to have_key('x-amz-website-redirect-location')
519
+
520
+ # Validate that the correct formats are used
521
+ expect(attributes).to have_key('content-md5')
522
+ expect(attributes).to have_key('website-redirect-location')
523
+ end
524
+ end
525
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ describe Middleman::S3SyncExtension do
4
+ let(:app) { double('app').as_null_object }
5
+
6
+ let(:extension) { described_class.new(app, {}) }
7
+
8
+ describe '#acl_enabled?' do
9
+ context 'when acl has default value' do
10
+ it 'returns true' do
11
+ expect(extension.acl_enabled?).to be true
12
+ end
13
+ end
14
+
15
+ context 'when acl is explicitly set to a value' do
16
+ let(:extension) { described_class.new(app, acl: 'private') }
17
+
18
+ it 'returns true' do
19
+ expect(extension.acl_enabled?).to be true
20
+ end
21
+ end
22
+
23
+ context 'when acl is set to nil' do
24
+ let(:extension) { described_class.new(app, acl: nil) }
25
+
26
+ it 'returns false' do
27
+ expect(extension.acl_enabled?).to be false
28
+ end
29
+ end
30
+
31
+ context 'when acl is set to empty string' do
32
+ let(:extension) { described_class.new(app, acl: '') }
33
+
34
+ it 'returns false' do
35
+ expect(extension.acl_enabled?).to be false
36
+ end
37
+ end
38
+
39
+ context 'when acl is set to false' do
40
+ let(:extension) { described_class.new(app, acl: false) }
41
+
42
+ it 'returns false' do
43
+ expect(extension.acl_enabled?).to be false
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#s3_sync_options' do
49
+ it 'returns the extension instance itself' do
50
+ expect(extension.s3_sync_options).to eq(extension)
51
+ end
52
+
53
+ it 'allows access to acl_enabled? through s3_sync_options' do
54
+ expect(extension.s3_sync_options.acl_enabled?).to be true
55
+ end
56
+ end
57
+
58
+ describe 'option delegation' do
59
+ let(:extension) do
60
+ described_class.new(app,
61
+ bucket: 'test-bucket',
62
+ region: 'us-west-2',
63
+ acl: 'public-read',
64
+ verbose: true
65
+ )
66
+ end
67
+
68
+ it 'delegates option readers to the options object' do
69
+ expect(extension.bucket).to eq('test-bucket')
70
+ expect(extension.region).to eq('us-west-2')
71
+ expect(extension.acl).to eq('public-read')
72
+ expect(extension.verbose).to be true
73
+ end
74
+
75
+ it 'responds to option methods' do
76
+ expect(extension.respond_to?(:bucket)).to be true
77
+ expect(extension.respond_to?(:region)).to be true
78
+ expect(extension.respond_to?(:acl)).to be true
79
+ expect(extension.respond_to?(:verbose)).to be true
80
+ end
81
+
82
+ it 'does not respond to non-existent methods' do
83
+ expect(extension.respond_to?(:nonexistent_method)).to be false
84
+ end
85
+
86
+ it 'raises NoMethodError for non-existent methods' do
87
+ expect { extension.nonexistent_method }.to raise_error(NoMethodError)
88
+ end
89
+ end
90
+
91
+ describe 'integration with S3Sync module' do
92
+ before do
93
+ allow(Middleman::Application).to receive(:root).and_return('/tmp')
94
+ allow(File).to receive(:exist?).with('/tmp/.s3_sync').and_return(false)
95
+ end
96
+
97
+ let(:extension) do
98
+ described_class.new(app,
99
+ bucket: 'test-bucket',
100
+ acl: 'private'
101
+ )
102
+ end
103
+
104
+ it 'sets s3_sync_options to the extension instance' do
105
+ extension.after_configuration
106
+ expect(Middleman::S3Sync.s3_sync_options).to eq(extension)
107
+ end
108
+
109
+ it 'allows S3Sync to access acl_enabled? through s3_sync_options' do
110
+ extension.after_configuration
111
+ expect(Middleman::S3Sync.s3_sync_options.acl_enabled?).to be true
112
+ end
113
+ end
114
+ end