sq-asset_sync 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +42 -0
  5. data/Appraisals +15 -0
  6. data/CHANGELOG.md +738 -0
  7. data/Gemfile +7 -0
  8. data/README.md +466 -0
  9. data/Rakefile +44 -0
  10. data/asset_sync.gemspec +38 -0
  11. data/docs/heroku.md +36 -0
  12. data/gemfiles/rails_3.1.gemfile +10 -0
  13. data/gemfiles/rails_3.2.gemfile +10 -0
  14. data/gemfiles/rails_4.0.gemfile +10 -0
  15. data/gemfiles/rails_4.1.gemfile +10 -0
  16. data/kochiku.yml +7 -0
  17. data/lib/asset_sync.rb +15 -0
  18. data/lib/asset_sync/asset_sync.rb +73 -0
  19. data/lib/asset_sync/config.rb +226 -0
  20. data/lib/asset_sync/engine.rb +53 -0
  21. data/lib/asset_sync/multi_mime.rb +16 -0
  22. data/lib/asset_sync/railtie.rb +5 -0
  23. data/lib/asset_sync/storage.rb +291 -0
  24. data/lib/asset_sync/version.rb +3 -0
  25. data/lib/generators/asset_sync/install_generator.rb +67 -0
  26. data/lib/generators/asset_sync/templates/asset_sync.rb +41 -0
  27. data/lib/generators/asset_sync/templates/asset_sync.yml +43 -0
  28. data/lib/tasks/asset_sync.rake +30 -0
  29. data/script/ci +31 -0
  30. data/spec/dummy_app/Rakefile +30 -0
  31. data/spec/dummy_app/app/assets/javascripts/application.js +1 -0
  32. data/spec/fixtures/aws_with_yml/config/asset_sync.yml +25 -0
  33. data/spec/fixtures/google_with_yml/config/asset_sync.yml +19 -0
  34. data/spec/fixtures/rackspace_with_yml/config/asset_sync.yml +20 -0
  35. data/spec/fixtures/with_invalid_yml/config/asset_sync.yml +24 -0
  36. data/spec/integration/aws_integration_spec.rb +77 -0
  37. data/spec/spec_helper.rb +64 -0
  38. data/spec/unit/asset_sync_spec.rb +257 -0
  39. data/spec/unit/google_spec.rb +142 -0
  40. data/spec/unit/multi_mime_spec.rb +48 -0
  41. data/spec/unit/rackspace_spec.rb +90 -0
  42. data/spec/unit/railsless_spec.rb +72 -0
  43. data/spec/unit/storage_spec.rb +244 -0
  44. metadata +248 -0
@@ -0,0 +1,142 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe AssetSync do
4
+ include_context "mock Rails without_yml"
5
+
6
+ describe 'with initializer' do
7
+ before(:each) do
8
+ AssetSync.config = AssetSync::Config.new
9
+ AssetSync.configure do |config|
10
+ config.fog_provider = 'Google'
11
+ config.google_storage_access_key_id = 'aaaa'
12
+ config.google_storage_secret_access_key = 'bbbb'
13
+ config.fog_directory = 'mybucket'
14
+ config.existing_remote_files = "keep"
15
+ end
16
+ end
17
+
18
+ it "should configure provider as Google" do
19
+ expect(AssetSync.config.fog_provider).to eq('Google')
20
+ expect(AssetSync.config).to be_google
21
+ end
22
+
23
+ it "should should keep existing remote files" do
24
+ expect(AssetSync.config.existing_remote_files?).to eq(true)
25
+ end
26
+
27
+ it "should configure google_storage_access_key_id" do
28
+ expect(AssetSync.config.google_storage_access_key_id).to eq("aaaa")
29
+ end
30
+
31
+ it "should configure google_storage_secret_access_key" do
32
+ expect(AssetSync.config.google_storage_secret_access_key).to eq("bbbb")
33
+ end
34
+
35
+ it "should configure fog_directory" do
36
+ expect(AssetSync.config.fog_directory).to eq("mybucket")
37
+ end
38
+
39
+ it "should configure existing_remote_files" do
40
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
41
+ end
42
+
43
+ it "should default gzip_compression to false" do
44
+ expect(AssetSync.config.gzip_compression).to be_falsey
45
+ end
46
+
47
+ it "should default manifest to false" do
48
+ expect(AssetSync.config.manifest).to be_falsey
49
+ end
50
+ end
51
+
52
+ describe 'from yml' do
53
+ before(:each) do
54
+ set_rails_root('google_with_yml')
55
+ AssetSync.config = AssetSync::Config.new
56
+ end
57
+
58
+ it "should configure google_storage_access_key_id" do
59
+ expect(AssetSync.config.google_storage_access_key_id).to eq("xxxx")
60
+ end
61
+
62
+ it "should configure google_storage_secret_access_key" do
63
+ expect(AssetSync.config.google_storage_secret_access_key).to eq("zzzz")
64
+ end
65
+
66
+ it "should configure google_storage_access_key" do
67
+ expect(AssetSync.config.fog_directory).to eq("rails_app_test")
68
+ end
69
+
70
+ it "should configure google_storage_access_key" do
71
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
72
+ end
73
+
74
+ it "should default gzip_compression to false" do
75
+ expect(AssetSync.config.gzip_compression).to be_falsey
76
+ end
77
+
78
+ it "should default manifest to false" do
79
+ expect(AssetSync.config.manifest).to be_falsey
80
+ end
81
+ end
82
+
83
+ describe 'with no configuration' do
84
+ before(:each) do
85
+ AssetSync.config = AssetSync::Config.new
86
+ end
87
+
88
+ it "should be invalid" do
89
+ expect{ AssetSync.sync }.to raise_error()
90
+ end
91
+ end
92
+
93
+ describe 'with fail_silent configuration' do
94
+ before(:each) do
95
+ allow(AssetSync).to receive(:stderr).and_return(StringIO.new)
96
+ AssetSync.config = AssetSync::Config.new
97
+ AssetSync.configure do |config|
98
+ config.fail_silently = true
99
+ end
100
+ end
101
+
102
+ it "should not raise an invalid exception" do
103
+ expect{ AssetSync.sync }.not_to raise_error()
104
+ end
105
+ end
106
+
107
+ describe 'with gzip_compression enabled' do
108
+ before(:each) do
109
+ AssetSync.config = AssetSync::Config.new
110
+ AssetSync.config.gzip_compression = true
111
+ end
112
+
113
+ it "config.gzip? should be true" do
114
+ expect(AssetSync.config.gzip?).to be_truthy
115
+ end
116
+ end
117
+
118
+ describe 'with manifest enabled' do
119
+ before(:each) do
120
+ AssetSync.config = AssetSync::Config.new
121
+ AssetSync.config.manifest = true
122
+ end
123
+
124
+ it "config.manifest should be true" do
125
+ expect(AssetSync.config.manifest).to be_truthy
126
+ end
127
+
128
+ it "config.manifest_path should default to public/assets.." do
129
+ expect(AssetSync.config.manifest_path).to match(/public\/assets\/manifest.yml/)
130
+ end
131
+
132
+ it "config.manifest_path should default to public/assets.." do
133
+ Rails.application.config.assets.manifest = "/var/assets"
134
+ expect(AssetSync.config.manifest_path).to eq("/var/assets/manifest.yml")
135
+ end
136
+
137
+ it "config.manifest_path should default to public/custom_assets.." do
138
+ Rails.application.config.assets.prefix = 'custom_assets'
139
+ expect(AssetSync.config.manifest_path).to match(/public\/custom_assets\/manifest.yml/)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe AssetSync::MultiMime do
4
+
5
+ before(:each) do
6
+ Object.send(:remove_const, :Rails) if defined?(Rails)
7
+ Object.send(:remove_const, :Mime) if defined?(Mime)
8
+ Object.send(:remove_const, :Rack) if defined?(Rack)
9
+ end
10
+
11
+ after(:each) do
12
+ Object.send(:remove_const, :Rails) if defined?(Rails)
13
+ Object.send(:remove_const, :Mime) if defined?(Mime)
14
+ Object.send(:remove_const, :Rack) if defined?(Rack)
15
+ end
16
+
17
+ after(:all) do
18
+ require 'mime/types'
19
+ end
20
+
21
+ describe 'Mime::Type' do
22
+
23
+ it 'should detect mime type' do
24
+ require 'rails'
25
+ expect(AssetSync::MultiMime.lookup('css')).to eq("text/css")
26
+ end
27
+
28
+ end
29
+
30
+ describe 'Rack::Mime' do
31
+
32
+ it 'should detect mime type' do
33
+ require 'rack/mime'
34
+ expect(AssetSync::MultiMime.lookup('css')).to eq("text/css")
35
+ end
36
+
37
+ end
38
+
39
+ describe 'MIME::Types' do
40
+
41
+ it 'should detect mime type' do
42
+ require 'mime/types'
43
+ expect(AssetSync::MultiMime.lookup('css')).to eq("text/css")
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe AssetSync do
4
+ include_context "mock Rails"
5
+
6
+ describe 'using Rackspace with initializer' do
7
+ before(:each) do
8
+ set_rails_root('without_yml')
9
+ AssetSync.config = AssetSync::Config.new
10
+ AssetSync.configure do |config|
11
+ config.fog_provider = 'Rackspace'
12
+ config.fog_directory = 'mybucket'
13
+ config.fog_region = 'dunno'
14
+ config.rackspace_username = 'aaaa'
15
+ config.rackspace_api_key = 'bbbb'
16
+ config.existing_remote_files = 'keep'
17
+ end
18
+ end
19
+
20
+ it "should configure provider as Rackspace" do
21
+ expect(AssetSync.config.fog_provider).to eq('Rackspace')
22
+ expect(AssetSync.config).to be_rackspace
23
+ end
24
+
25
+ it "should keep existing remote files" do
26
+ expect(AssetSync.config.existing_remote_files?).to eq(true)
27
+ end
28
+
29
+ it "should configure rackspace_username" do
30
+ expect(AssetSync.config.rackspace_username).to eq("aaaa")
31
+ end
32
+
33
+ it "should configure rackspace_api_key" do
34
+ expect(AssetSync.config.rackspace_api_key).to eq("bbbb")
35
+ end
36
+
37
+ it "should configure fog_directory" do
38
+ expect(AssetSync.config.fog_directory).to eq("mybucket")
39
+ end
40
+
41
+ it "should configure fog_region" do
42
+ expect(AssetSync.config.fog_region).to eq("dunno")
43
+ end
44
+
45
+ it "should configure existing_remote_files" do
46
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
47
+ end
48
+
49
+ it "should configure existing_remote_files" do
50
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
51
+ end
52
+
53
+ it "should default rackspace_auth_url to false" do
54
+ expect(AssetSync.config.rackspace_auth_url).to be_falsey
55
+ end
56
+
57
+ end
58
+
59
+ describe 'using Rackspace from yml' do
60
+
61
+ before(:each) do
62
+ set_rails_root('rackspace_with_yml')
63
+ AssetSync.config = AssetSync::Config.new
64
+ end
65
+
66
+ it "should keep existing remote files" do
67
+ expect(AssetSync.config.existing_remote_files?).to eq(true)
68
+ end
69
+
70
+ it "should configure rackspace_username" do
71
+ expect(AssetSync.config.rackspace_username).to eq("xxxx")
72
+ end
73
+
74
+ it "should configure rackspace_api_key" do
75
+ expect(AssetSync.config.rackspace_api_key).to eq("zzzz")
76
+ end
77
+
78
+ it "should configure fog_directory" do
79
+ expect(AssetSync.config.fog_directory).to eq("rails_app_test")
80
+ end
81
+
82
+ it "should configure fog_region" do
83
+ expect(AssetSync.config.fog_region).to eq("eu-west-1")
84
+ end
85
+
86
+ it "should configure existing_remote_files" do
87
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe AssetSync do
4
+ include_context "mock without Rails"
5
+
6
+ describe 'with initializer' do
7
+ before(:each) do
8
+ AssetSync.config = AssetSync::Config.new
9
+ AssetSync.configure do |config|
10
+ config.fog_provider = 'AWS'
11
+ config.aws_access_key_id = 'aaaa'
12
+ config.aws_secret_access_key = 'bbbb'
13
+ config.fog_directory = 'mybucket'
14
+ config.fog_region = 'eu-west-1'
15
+ config.existing_remote_files = "keep"
16
+ config.prefix = "assets"
17
+ config.public_path = Pathname("./public")
18
+ end
19
+ end
20
+
21
+ it "should have prefix of assets" do
22
+ expect(AssetSync.config.prefix).to eq("assets")
23
+ end
24
+
25
+ it "should have prefix of assets" do
26
+ expect(AssetSync.config.public_path.to_s).to eq("./public")
27
+ end
28
+
29
+ it "should default AssetSync to enabled" do
30
+ expect(AssetSync.config.enabled?).to be_truthy
31
+ expect(AssetSync.enabled?).to be_truthy
32
+ end
33
+
34
+ it "should configure provider as AWS" do
35
+ expect(AssetSync.config.fog_provider).to eq('AWS')
36
+ expect(AssetSync.config).to be_aws
37
+ end
38
+
39
+ it "should should keep existing remote files" do
40
+ expect(AssetSync.config.existing_remote_files?).to eq(true)
41
+ end
42
+
43
+ it "should configure aws_access_key" do
44
+ expect(AssetSync.config.aws_access_key_id).to eq("aaaa")
45
+ end
46
+
47
+ it "should configure aws_secret_access_key" do
48
+ expect(AssetSync.config.aws_secret_access_key).to eq("bbbb")
49
+ end
50
+
51
+ it "should configure aws_access_key" do
52
+ expect(AssetSync.config.fog_directory).to eq("mybucket")
53
+ end
54
+
55
+ it "should configure fog_region" do
56
+ expect(AssetSync.config.fog_region).to eq("eu-west-1")
57
+ end
58
+
59
+ it "should configure existing_remote_files" do
60
+ expect(AssetSync.config.existing_remote_files).to eq("keep")
61
+ end
62
+
63
+ it "should default gzip_compression to false" do
64
+ expect(AssetSync.config.gzip_compression).to be_falsey
65
+ end
66
+
67
+ it "should default manifest to false" do
68
+ expect(AssetSync.config.manifest).to be_falsey
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,244 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe AssetSync::Storage do
4
+ include_context "mock Rails without_yml"
5
+
6
+ describe '#upload_files' do
7
+ before(:each) do
8
+ @local_files = ["local_image2.jpg", "assets/manifest-abc.json", "local_image1.jpg", "local_stylesheet1.css", "local_stylesheet2.css"]
9
+ @remote_files = ["local_image.jpg", "local_stylesheet1.css"]
10
+ @config = AssetSync::Config.new
11
+ end
12
+
13
+ it 'always uploads the manifest last', test: true do
14
+ expect(@config).to receive(:manifest_digest_path).and_return('assets/manifest-abc.json')
15
+
16
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
17
+
18
+ storage = AssetSync::Storage.new(@config)
19
+ allow(storage).to receive(:local_files).and_return(@local_files)
20
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
21
+ expect(storage).to receive(:upload_file).ordered.with('local_image2.jpg')
22
+ expect(storage).to receive(:upload_file).ordered.with('local_image1.jpg')
23
+ expect(storage).to receive(:upload_file).ordered.with('local_stylesheet2.css')
24
+ expect(storage).to receive(:upload_file).ordered.with('assets/manifest.json')
25
+ expect(storage).to receive(:upload_file).ordered.with('assets/manifest-abc.json')
26
+
27
+ storage.upload_files
28
+ end
29
+
30
+ context 'with the manifest on the remote', test: true do
31
+ before do
32
+ @remote_files << 'manifest-abc.json'
33
+ end
34
+
35
+ it 'does not upload' do
36
+ expect(@config).to receive(:manifest_digest_path).and_return('assets/manifest-abc.json')
37
+
38
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
39
+
40
+ storage = AssetSync::Storage.new(@config)
41
+
42
+ conn_mock = double
43
+ allow(storage).to receive(:connection).and_return(conn_mock)
44
+ expect(conn_mock).to receive(:head_object).with(@config.fog_directory, 'assets/manifest-abc.json').and_return(
45
+ double(headers: { 'Last-Modified' => CGI.rfc1123_date(Time.now.utc) })
46
+ )
47
+ allow(storage).to receive(:local_files).and_return(@local_files)
48
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
49
+ expect(storage).to_not receive(:upload_file)
50
+
51
+ storage.upload_files
52
+ end
53
+ end
54
+
55
+ it 'should overwrite all remote files if set to ignore' do
56
+ @config.existing_remote_files = 'ignore'
57
+ storage = AssetSync::Storage.new(@config)
58
+ allow(storage).to receive(:local_files).and_return(@local_files)
59
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
60
+
61
+ @local_files.each do |file|
62
+ expect(storage).to receive(:upload_file).with(file)
63
+ end
64
+
65
+ expect(storage).to receive(:upload_file).ordered.with('assets/manifest.json')
66
+ storage.upload_files
67
+ end
68
+
69
+ it 'should allow force overwriting of specific files' do
70
+ @config.always_upload = ['local_image.jpg']
71
+
72
+ storage = AssetSync::Storage.new(@config)
73
+ allow(storage).to receive(:local_files).and_return(@local_files)
74
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
75
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
76
+
77
+ (@local_files - @remote_files + storage.always_upload_files).each do |file|
78
+ expect(storage).to receive(:upload_file).with(file)
79
+ end
80
+
81
+ expect(storage).to receive(:upload_file).ordered.with('assets/manifest.json')
82
+ storage.upload_files
83
+ end
84
+
85
+ it 'should allow to ignore files' do
86
+ @config.ignored_files = ['local_image1.jpg', /local_stylesheet\d\.css/]
87
+
88
+ storage = AssetSync::Storage.new(@config)
89
+ allow(storage).to receive(:local_files).and_return(@local_files)
90
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
91
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
92
+
93
+ (@local_files - @remote_files - storage.ignored_files + storage.always_upload_files).each do |file|
94
+ expect(storage).to receive(:upload_file).with(file)
95
+ end
96
+
97
+ expect(storage).to receive(:upload_file).ordered.with('assets/manifest.json')
98
+ storage.upload_files
99
+ end
100
+
101
+ it 'should upload updated non-fingerprinted files' do
102
+ @local_files = [
103
+ 'public/image.png',
104
+ 'public/image-82389298328.png',
105
+ 'public/image-a8389f9h324.png',
106
+ 'public/application.js',
107
+ 'public/application-b3389d983k1.js',
108
+ 'public/application-ac387d53f31.js',
109
+ 'public',
110
+ ]
111
+ @remote_files = [
112
+ 'public/image.png',
113
+ 'public/image-a8389f9h324.png',
114
+ 'public/application.js',
115
+ 'public/application-b3389d983k1.js',
116
+ ]
117
+
118
+ storage = AssetSync::Storage.new(@config)
119
+ allow(storage).to receive(:local_files).and_return(@local_files)
120
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
121
+ allow(File).to receive(:file?).and_return(true) # Pretend they all exist
122
+
123
+ updated_nonfingerprinted_files = [
124
+ 'public/image.png',
125
+ 'public/application.js',
126
+ ]
127
+ (@local_files - @remote_files + updated_nonfingerprinted_files).each do |file|
128
+ expect(storage).to receive(:upload_file).with(file)
129
+ end
130
+ storage.upload_files
131
+ end
132
+
133
+ it 'should correctly set expire date' do
134
+ local_files = ['file1.jpg', 'file1-1234567890abcdef1234567890abcdef.jpg',
135
+ 'file1-1234567890abcdef1234567890abcdef.jpg.gz']
136
+ local_files += ['dir1/dir2/file2.jpg', 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg',
137
+ 'dir1/dir2/file2-1234567890abcdef1234567890abcdef.jpg.gz']
138
+ remote_files = []
139
+ storage = AssetSync::Storage.new(@config)
140
+ allow(storage).to receive(:local_files).and_return(local_files)
141
+ allow(storage).to receive(:get_remote_files).and_return(remote_files)
142
+ allow(File).to receive(:file?).and_return(true)
143
+ allow(File).to receive(:open).and_return(nil)
144
+
145
+ def check_file(file)
146
+ case file[:key]
147
+ when 'file1.jpg'
148
+ when 'dir1/dir2/file2.jpg'
149
+ !expect(file).not_to include(:cache_control, :expires)
150
+ when %r|file1-1234567890abcdef1234567890abcdef\.jpg|
151
+ when %r|dir1/dir2/file2-1234567890abcdef1234567890abcdef\.jpg|
152
+ expect(file).to include(:cache_control, :expires)
153
+ file.should include(:cache_control, :expires)
154
+ else
155
+ fail
156
+ end
157
+ end
158
+
159
+ files = double()
160
+ local_files.count.times do
161
+ expect(files).to receive(:create) { |file| check_file(file) }
162
+ end
163
+ allow(storage).to receive_message_chain(:bucket, :files).and_return(files)
164
+ storage.upload_files
165
+ end
166
+
167
+ it "shoud invalidate files" do
168
+ @config.cdn_distribution_id = "1234"
169
+ @config.invalidate = ['local_image1.jpg']
170
+ @config.fog_provider = 'AWS'
171
+
172
+ storage = AssetSync::Storage.new(@config)
173
+ allow(storage).to receive(:local_files).and_return(@local_files)
174
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
175
+ allow(storage).to receive(:upload_file).and_return(true)
176
+
177
+ mock_cdn = double
178
+ expect(Fog::CDN).to receive(:new).and_return(mock_cdn)
179
+ expect(mock_cdn).to receive(:post_invalidation).with("1234", ["/assets/local_image1.jpg"]).and_return(double({:body => {:id => '1234'}}))
180
+
181
+ storage.upload_files
182
+ end
183
+ end
184
+
185
+ describe '#upload_file' do
186
+ before(:each) do
187
+ # Object#remove_const does not remove the loaded
188
+ # file from the $" variable
189
+ #Object.send(:remove_const, :MIME) if defined?(MIME)
190
+ mime_types = $".grep(/mime\/types/).first
191
+ $".delete(mime_types)
192
+ require 'mime/types'
193
+ @config = AssetSync::Config.new
194
+ end
195
+
196
+ it 'accepts custom headers per file' do
197
+ @config.custom_headers = {
198
+ "local_image2.jpg" => {
199
+ :cache_control => 'max-age=0'
200
+ }
201
+ }
202
+ storage = AssetSync::Storage.new(@config)
203
+ allow(storage).to receive(:local_files).and_return(@local_files)
204
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
205
+ allow(File).to receive(:open).and_return('file') # Pretend they all exist
206
+
207
+ bucket = double
208
+ files = double
209
+
210
+ allow(storage).to receive(:bucket).and_return(bucket)
211
+ allow(bucket).to receive(:files).and_return(files)
212
+
213
+ expect(files).to receive(:create) do |argument|
214
+ expect(argument[:cache_control]).to eq('max-age=0')
215
+ end
216
+ storage.upload_file('assets/local_image2.jpg')
217
+ end
218
+
219
+ it 'accepts custom headers with a regular expression' do
220
+ @config.custom_headers = {
221
+ ".*\.jpg" => {
222
+ :cache_control => 'max-age=0'
223
+ }
224
+ }
225
+ storage = AssetSync::Storage.new(@config)
226
+ allow(storage).to receive(:local_files).and_return(@local_files)
227
+ allow(storage).to receive(:get_remote_files).and_return(@remote_files)
228
+ allow(File).to receive(:open).and_return('file') # Pretend they all exist
229
+ bucket = double
230
+ files = double
231
+ allow(storage).to receive(:bucket).and_return(bucket)
232
+ allow(bucket).to receive(:files).and_return(files)
233
+
234
+ expect(files).to receive(:create) do |argument|
235
+ expect(argument[:cache_control]).to eq('max-age=0')
236
+ end
237
+ storage.upload_file('assets/some_longer_path/local_image2.jpg')
238
+ end
239
+
240
+ after(:each) do
241
+ #Object.send(:remove_const, :MIME) if defined?(MIME)
242
+ end
243
+ end
244
+ end