saviour 0.2.0

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 +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +491 -0
  7. data/Rakefile +6 -0
  8. data/lib/saviour.rb +170 -0
  9. data/lib/saviour/base_uploader.rb +81 -0
  10. data/lib/saviour/config.rb +13 -0
  11. data/lib/saviour/file.rb +124 -0
  12. data/lib/saviour/local_storage.rb +72 -0
  13. data/lib/saviour/processors/digest.rb +16 -0
  14. data/lib/saviour/s3_storage.rb +77 -0
  15. data/lib/saviour/string_source.rb +15 -0
  16. data/lib/saviour/uploader/element.rb +19 -0
  17. data/lib/saviour/uploader/processors_runner.rb +88 -0
  18. data/lib/saviour/uploader/store_dir_extractor.rb +41 -0
  19. data/lib/saviour/url_source.rb +55 -0
  20. data/lib/saviour/version.rb +3 -0
  21. data/saviour.gemspec +26 -0
  22. data/spec/feature/access_to_model_and_mounted_as.rb +30 -0
  23. data/spec/feature/crud_workflows_spec.rb +138 -0
  24. data/spec/feature/persisted_path_spec.rb +35 -0
  25. data/spec/feature/reload_model_spec.rb +25 -0
  26. data/spec/feature/validations_spec.rb +172 -0
  27. data/spec/feature/versions_spec.rb +186 -0
  28. data/spec/models/base_uploader_spec.rb +396 -0
  29. data/spec/models/config_spec.rb +16 -0
  30. data/spec/models/file_spec.rb +210 -0
  31. data/spec/models/local_storage_spec.rb +154 -0
  32. data/spec/models/processors/digest_spec.rb +22 -0
  33. data/spec/models/s3_storage_spec.rb +170 -0
  34. data/spec/models/saviour_spec.rb +80 -0
  35. data/spec/models/url_source_spec.rb +76 -0
  36. data/spec/spec_helper.rb +93 -0
  37. data/spec/support/data/camaloon.jpg +0 -0
  38. data/spec/support/data/example.xml +21 -0
  39. data/spec/support/data/text.txt +1 -0
  40. data/spec/support/models.rb +3 -0
  41. data/spec/support/schema.rb +9 -0
  42. metadata +196 -0
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Saviour do
4
+ it "raises error if included in a non active record class" do
5
+ expect {
6
+ Class.new do
7
+ include Saviour
8
+ end
9
+ }.to raise_error(Saviour::NoActiveRecordDetected)
10
+ end
11
+
12
+ it "error if column not present" do
13
+ expect {
14
+ Class.new(Test) do
15
+ include Saviour
16
+
17
+ attach_file :not_present, Saviour::BaseUploader
18
+ end
19
+ }.to raise_error(RuntimeError)
20
+ end
21
+
22
+ context do
23
+ it "error if column not present on version" do
24
+ uploader = Class.new(Saviour::BaseUploader) do
25
+ store_dir { "/store/dir" }
26
+
27
+ version(:thumb) do
28
+ store_dir { "/versions/store/dir" }
29
+ end
30
+
31
+ version(:not_present)
32
+ end
33
+
34
+ expect {
35
+ Class.new(Test) do
36
+ include Saviour
37
+
38
+ attach_file :file, uploader
39
+ end
40
+ }.to raise_error(RuntimeError)
41
+ end
42
+ end
43
+
44
+ it "does not raise error if table is not present" do
45
+ allow(Test).to receive(:table_exists?).and_return(false)
46
+
47
+ expect {
48
+ Class.new(Test) do
49
+ include Saviour
50
+
51
+ attach_file :not_present, Saviour::BaseUploader
52
+ end
53
+ }.to_not raise_error
54
+ end
55
+
56
+ describe ".attached_files" do
57
+ it "includes a mapping of the currently attached files and their versions" do
58
+ uploader = Class.new(Saviour::BaseUploader) do
59
+ store_dir { "/store/dir" }
60
+
61
+ version(:thumb)
62
+ version(:thumb_2)
63
+ end
64
+
65
+ klass = Class.new(Test) do
66
+ include Saviour
67
+ attach_file :file, uploader
68
+ end
69
+
70
+ expect(klass.attached_files).to eq({file: [:thumb, :thumb_2]})
71
+
72
+ klass2 = Class.new(Test) do
73
+ include Saviour
74
+ attach_file :file, Saviour::BaseUploader
75
+ end
76
+
77
+ expect(klass2.attached_files).to eq({file: []})
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Saviour::UrlSource do
4
+ describe "initialization" do
5
+ it "fails if no valid uri" do
6
+ expect { Saviour::UrlSource.new("%^7QQ#%%@#@@") }.to raise_error(ArgumentError).with_message(/is not a valid URI/)
7
+ end
8
+
9
+ it "does not fail if provided a valid uri" do
10
+ expect(Saviour::UrlSource.new("http://domain.com/file.jpg")).to be_truthy
11
+ end
12
+ end
13
+
14
+ describe "#original_filename" do
15
+ it "is extracted from the passed uri" do
16
+ a = Saviour::UrlSource.new("http://domain.com/file.jpg")
17
+ expect(a.original_filename).to eq "file.jpg"
18
+ end
19
+ end
20
+
21
+ describe "#path" do
22
+ it "is extracted from te passed uri" do
23
+ a = Saviour::UrlSource.new("http://domain.com/path/file.jpg")
24
+ expect(a.path).to eq "/path/file.jpg"
25
+ end
26
+ end
27
+
28
+ describe "#read" do
29
+ it "fails if the uri cannot be accessed" do
30
+ allow(Net::HTTP).to receive(:get_response).and_return(Net::HTTPNotFound)
31
+
32
+ a = Saviour::UrlSource.new("http://aboubaosdubioaubosdubaou.com/path/file.jpg")
33
+ expect { a.read }.to raise_error(RuntimeError).with_message(/failed after 3 attempts/)
34
+ end
35
+
36
+ it "retries the request 3 times on error" do
37
+ expect(Net::HTTP).to receive(:get_response).and_return(Net::HTTPNotFound, Net::HTTPNotFound)
38
+ expect(Net::HTTP).to receive(:get_response).and_call_original
39
+ a = Saviour::UrlSource.new("http://example.com/")
40
+ expect(a.read.length).to be > 100
41
+ end
42
+
43
+ it "succeds if the uri is valid" do
44
+ a = Saviour::UrlSource.new("http://example.com/")
45
+ expect(a.read.length).to be > 100
46
+ end
47
+
48
+ it "follows redirects" do
49
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
50
+ expect(response).to receive(:[]).with("location").and_return("http://example.com")
51
+
52
+ expect(Net::HTTP).to receive(:get_response).and_return(response)
53
+ expect(Net::HTTP).to receive(:get_response).and_call_original
54
+
55
+ a = Saviour::UrlSource.new("http://faked.blabla")
56
+ expect(a.read.length).to be > 100
57
+ end
58
+
59
+ it "does not follow more than 10 redirects" do
60
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
61
+ expect(response).to receive(:[]).with("location").exactly(10).times.and_return("http://example.com")
62
+ expect(Net::HTTP).to receive(:get_response).exactly(10).times.and_return(response)
63
+
64
+ expect { Saviour::UrlSource.new("http://faked.blabla").read }.to raise_error(RuntimeError).with_message(/Max number of allowed redirects reached \(10\) when resolving/)
65
+ end
66
+
67
+ it "fails if the redirected location is not a valid URI" do
68
+ response = Net::HTTPRedirection.new "1.1", "301", "Redirect"
69
+ expect(response).to receive(:[]).with("location").and_return("http://example.com/%@(&#<<<<")
70
+
71
+ expect(Net::HTTP).to receive(:get_response).and_return(response)
72
+
73
+ expect { Saviour::UrlSource.new("http://faked.blabla").read }.to raise_error(ArgumentError).with_message(/is not a valid URI/)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,93 @@
1
+ require "codeclimate-test-reporter"
2
+ CodeClimate::TestReporter.start
3
+
4
+ require 'bundler/setup'
5
+ require 'rspec'
6
+ require 'active_record'
7
+ require 'sqlite3'
8
+ require 'logger'
9
+
10
+ require File.expand_path("../../lib/saviour", __FILE__)
11
+
12
+ connection_opts = case ENV.fetch('DB', "sqlite")
13
+ when "sqlite"
14
+ {adapter: "sqlite3", database: ":memory:"}
15
+ when "mysql"
16
+ {adapter: "mysql2", database: "saviour", username: "root", encoding: "utf8"}
17
+ when "postgres"
18
+ {adapter: "postgresql", database: "saviour", username: "postgres"}
19
+ end
20
+
21
+ ActiveRecord::Base.establish_connection(connection_opts)
22
+
23
+ ActiveRecord::Base.logger = Logger.new(STDOUT) if ENV['DEBUG']
24
+ silence_stream(STDOUT) { require 'support/schema' }
25
+ require 'support/models'
26
+
27
+ RSpec.configure do |config|
28
+ config.around do |example|
29
+ Fog.mock!
30
+
31
+ Dir.mktmpdir { |dir|
32
+ @tmpdir = dir
33
+ example.run
34
+ }
35
+ end
36
+ end
37
+
38
+ def with_tempfile(ext = ".jpg")
39
+ Tempfile.open(["random", ext], @tmpdir) do |temp|
40
+ yield(temp)
41
+ end
42
+ end
43
+
44
+ def with_test_file(name)
45
+ file_path = File.join(File.expand_path("spec/support/data"), name)
46
+
47
+ basename = File.basename file_path, ".*"
48
+ Tempfile.open([basename, File.extname(file_path)], @tmpdir) do |temp|
49
+ temp.write File.read(file_path)
50
+ temp.flush
51
+ temp.rewind
52
+
53
+ yield(temp, File.basename(temp.path))
54
+ end
55
+ end
56
+
57
+ class MockedS3Helper
58
+ attr_reader :directory
59
+
60
+ def start!(bucket_name: nil)
61
+ @directory = connection.directories.create(key: bucket_name)
62
+ end
63
+
64
+ def write(contents, path)
65
+ directory.files.create(
66
+ key: path,
67
+ body: contents,
68
+ public: true
69
+ )
70
+ end
71
+
72
+ def read(path)
73
+ directory.files.get(path).body
74
+ end
75
+
76
+ def delete(path)
77
+ directory.files.get(path).destroy
78
+ end
79
+
80
+ def exists?(path)
81
+ !!directory.files.head(path)
82
+ end
83
+
84
+ def public_url(path)
85
+ directory.files.get(path).public_url
86
+ end
87
+
88
+ private
89
+
90
+ def connection
91
+ @connection ||= Fog::Storage.new(provider: 'AWS', aws_access_key_id: "stub", aws_secret_access_key: "stub")
92
+ end
93
+ end
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0"?>
2
+ <Order>
3
+ <Date>2003/07/04</Date>
4
+ <CustomerId>123</CustomerId>
5
+ <CustomerName>Acme Alpha</CustomerName>
6
+ <Item>
7
+ <ItemId> 987</ItemId>
8
+ <ItemName>Coupler</ItemName>
9
+ <Quantity>5</Quantity>
10
+ </Item>
11
+ <Item>
12
+ <ItemId>654</ItemId>
13
+ <ItemName>Connector</ItemName>
14
+ <Quantity unit="12">3</Quantity>
15
+ </Item>
16
+ <Item>
17
+ <ItemId>579</ItemId>
18
+ <ItemName>Clasp</ItemName>
19
+ <Quantity>1</Quantity>
20
+ </Item>
21
+ </Order>
@@ -0,0 +1 @@
1
+ Hello world
@@ -0,0 +1,3 @@
1
+ class Test < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,9 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :tests do |t|
3
+ t.string :file
4
+ t.string :file_thumb
5
+ t.string :file_thumb_2
6
+ t.string :name
7
+ t.timestamps null: false
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: saviour
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Roger Campos
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fog-aws
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mime-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sqlite3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: File storage handler following active record model lifecycle
126
+ email:
127
+ - roger@rogercampos.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - lib/saviour.rb
139
+ - lib/saviour/base_uploader.rb
140
+ - lib/saviour/config.rb
141
+ - lib/saviour/file.rb
142
+ - lib/saviour/local_storage.rb
143
+ - lib/saviour/processors/digest.rb
144
+ - lib/saviour/s3_storage.rb
145
+ - lib/saviour/string_source.rb
146
+ - lib/saviour/uploader/element.rb
147
+ - lib/saviour/uploader/processors_runner.rb
148
+ - lib/saviour/uploader/store_dir_extractor.rb
149
+ - lib/saviour/url_source.rb
150
+ - lib/saviour/version.rb
151
+ - saviour.gemspec
152
+ - spec/feature/access_to_model_and_mounted_as.rb
153
+ - spec/feature/crud_workflows_spec.rb
154
+ - spec/feature/persisted_path_spec.rb
155
+ - spec/feature/reload_model_spec.rb
156
+ - spec/feature/validations_spec.rb
157
+ - spec/feature/versions_spec.rb
158
+ - spec/models/base_uploader_spec.rb
159
+ - spec/models/config_spec.rb
160
+ - spec/models/file_spec.rb
161
+ - spec/models/local_storage_spec.rb
162
+ - spec/models/processors/digest_spec.rb
163
+ - spec/models/s3_storage_spec.rb
164
+ - spec/models/saviour_spec.rb
165
+ - spec/models/url_source_spec.rb
166
+ - spec/spec_helper.rb
167
+ - spec/support/data/camaloon.jpg
168
+ - spec/support/data/example.xml
169
+ - spec/support/data/text.txt
170
+ - spec/support/models.rb
171
+ - spec/support/schema.rb
172
+ homepage: https://github.com/rogercampos/saviour
173
+ licenses:
174
+ - MIT
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: 2.0.0
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ requirements: []
191
+ rubyforge_project:
192
+ rubygems_version: 2.5.1
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: File storage handler following active record model lifecycle
196
+ test_files: []