carrierwave-neo4j 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module CarrierWave
2
2
  module Neo4j
3
- VERSION = "2.0.0"
3
+ VERSION = '3.0.0'
4
4
  end
5
5
  end
Binary file
Binary file
@@ -0,0 +1,29 @@
1
+
2
+ require "neo4j"
3
+
4
+ class DatabaseCleaner
5
+ include Neo4j::Migrations::Helpers
6
+
7
+ def self.clean
8
+ DatabaseCleaner.new.clean_db
9
+ end
10
+
11
+ def self.avoid_validation
12
+ # migrations and db cleanup have to happen outside of validations
13
+ # or they never succeed
14
+ Neo4j::Migrations.currently_running_migrations = true
15
+ yield
16
+ Neo4j::Migrations.currently_running_migrations = false
17
+ end
18
+
19
+ def clean_db
20
+ execute("match (n) detach delete n;")
21
+ execute("call db.constraints").each do |constraint|
22
+ execute "drop #{constraint[:description]}"
23
+ end
24
+ execute("call db.indexes").each do |index|
25
+ execute "drop #{index[:description]}"
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FakeBookMigration < Neo4j::Migrations::Base
5
+
6
+ def self.create
7
+ FakeBookMigration.new(:fake_book_migration)
8
+ end
9
+
10
+ def up
11
+ add_constraint :Book, :uuid, force: true
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require 'helpers/fake_schema_migration'
3
+ require 'helpers/fake_user_migration'
4
+ require 'helpers/fake_book_migration'
5
+
6
+ class FakeMigrations
7
+ def self.migrate(direction)
8
+ FakeSchemaMigration.create.migrate(direction)
9
+ FakeUserMigration.create.migrate(direction)
10
+ FakeBookMigration.create.migrate(direction)
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FakeSchemaMigration < Neo4j::Migrations::Base
5
+
6
+ def self.create
7
+ FakeSchemaMigration.new(:fake_schema_migration)
8
+ end
9
+
10
+ def up
11
+ add_constraint :"Neo4j::Migrations::SchemaMigration", :migration_id, force: true
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FakeUserMigration < Neo4j::Migrations::Base
5
+
6
+ def self.create
7
+ FakeUserMigration.new(:fake_user_migration)
8
+ end
9
+
10
+ def up
11
+ add_constraint :User, :uuid, force: true
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+
2
+ require "neo4j"
3
+
4
+ class FilesystemCleaner
5
+ def self.clean
6
+ FilesystemCleaner.new.clean_fs
7
+ end
8
+
9
+ def clean_fs
10
+ FileUtils.rm_rf("spec/public/uploads")
11
+ end
12
+ end
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+
3
+ # RealisticUploader and Book exist to provide a basic test harness with
4
+ # standard Ruby code and no metaprogramming of any sort. Because that
5
+ # stuff is really hard to trust, even when you're sure you got it right.
6
+
7
+ class RealisticUploader < CarrierWave::Uploader::Base
8
+ include CarrierWave::MiniMagick
9
+
10
+ storage :file
11
+
12
+ def store_dir
13
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
14
+ end
15
+
16
+ def extension_whitelist
17
+ %w(jpg jpeg gif png)
18
+ end
19
+ end
20
+
21
+ class Book
22
+ include Neo4j::ActiveNode
23
+ property :cover, type: String
24
+ mount_uploader :cover, RealisticUploader
25
+ end
26
+
27
+ describe CarrierWave::Neo4j do
28
+ after do
29
+ Book.destroy_all
30
+ end
31
+
32
+ describe "#uploader" do
33
+ let(:book) { Book.new }
34
+ subject { book.cover }
35
+
36
+ context "when nothing is assigned" do
37
+ it { should be_blank }
38
+ end
39
+
40
+ context "when a file is stored to a store_dir" do
41
+ before do
42
+ book.cover = File.open(file_path("ong.jpg"))
43
+ book.save
44
+ book.reload
45
+ end
46
+
47
+ it { should be_an_instance_of RealisticUploader }
48
+ its(:current_path) { should == public_path("uploads/book/cover/#{book.id}/ong.jpg") }
49
+ end
50
+
51
+ context "when a db lookup uses `#find`" do
52
+ before do
53
+ book.cover = File.open(file_path("ong.jpg"))
54
+ book.save
55
+ @found = Book.find(book.id)
56
+ end
57
+
58
+ it "has a basic identifier" do
59
+ expect(@found.cover_identifier).to eq "ong.jpg"
60
+ end
61
+
62
+ subject { @found.cover }
63
+
64
+ it { should be_an_instance_of RealisticUploader }
65
+ its(:url) { should == "/uploads/book/cover/#{book.id}/ong.jpg"}
66
+ its(:current_path) { should == public_path("uploads/book/cover/#{book.id}/ong.jpg") }
67
+ end
68
+
69
+ context "when a db look up does not use `#find`" do
70
+ before do
71
+ book.cover = File.open(file_path("ong.jpg"))
72
+ book.save
73
+ @found = Book.find_by_id(book.id)
74
+ end
75
+
76
+ it "has a basic identifier" do
77
+ expect(@found.cover_identifier).to eq "ong.jpg"
78
+ end
79
+
80
+ subject { @found.cover }
81
+
82
+ # There is no way around this. `#url` and `#current_path` depend on the
83
+ # retrieval of the file from the store but there the only callback
84
+ # available is `:after_find` which does not fire on `#find_by` queries.
85
+ it { should be_an_instance_of RealisticUploader }
86
+ its(:url) { should be_nil }
87
+ its(:current_path) { should be_nil }
88
+
89
+ it "is retrieved with `#reload_from_database!`" do
90
+ @found.reload_from_database!
91
+ expect(@found.cover.url).to eq("/uploads/book/cover/#{@found.id}/ong.jpg")
92
+ expect(@found.cover.current_path).to eq(public_path("uploads/book/cover/#{@found.id}/ong.jpg"))
93
+ end
94
+ end
95
+
96
+ context "with CarrierWave::MiniMagick" do
97
+ it "has width and height" do
98
+ book.cover = File.open(file_path("ong.jpg"))
99
+ expect(book.cover.width).to eq 273
100
+ expect(book.cover.height).to eq 273
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,137 @@
1
+ require "spec_helper"
2
+
3
+ # This spec mirrors the specs found in the CarrierWave::Orm::ActiveRecord spec:
4
+ # https://github.com/carrierwaveuploader/carrierwave/blob/master/spec/orm/activerecord_spec.rb
5
+ #
6
+ # Use it to sanity-check behaviour since ActiveGraph and ActiveRecord are
7
+ # NOT symmetrical.
8
+
9
+ class DefaultUploader < CarrierWave::Uploader::Base ; end
10
+
11
+ def reset_class
12
+ Object.send(:remove_const, "User") rescue nil
13
+ Object.const_set("User", Class.new())
14
+ User.class_eval do
15
+ include Neo4j::ActiveNode
16
+ property :image, type: String
17
+ mount_uploader :image, DefaultUploader
18
+ end
19
+ User
20
+ end
21
+
22
+ describe CarrierWave::Neo4j do
23
+ before do
24
+ reset_class
25
+ @user = User.new
26
+ end
27
+
28
+ after do
29
+ User.destroy_all
30
+ end
31
+
32
+ describe "sanity checks" do
33
+
34
+ describe "#mount_uploader" do
35
+ before do
36
+ User.mount_uploader(:image, DefaultUploader)
37
+ @user = User.new
38
+ end
39
+
40
+ it "returns valid JSON when to_json is called when image is nil" do
41
+ expect(@user[:image]).to be_blank
42
+ hash = JSON.parse(@user.to_json)
43
+ expect(hash.keys).to include("user")
44
+ # ActiveRecord returns the user hash directly but Neo4j's `.to_json`
45
+ # requires that we select the user hash explicitly
46
+ user_hash = hash["user"]
47
+ expect(user_hash.keys).to include("image")
48
+ expect(user_hash["image"].keys).to include("url")
49
+ expect(user_hash["image"]["url"]).to be_nil
50
+ end
51
+
52
+ it "returns valid JSON when to_json is called when image is present" do
53
+ @user.image = File.open(file_path("ong.jpg"))
54
+ @user.save!
55
+ @user.reload
56
+ # again, ActiveRecord does not require the sub-select with `["user"]`
57
+ expect(JSON.parse(@user.to_json)["user"]["image"]).to eq({"url" => "/uploads/ong.jpg"})
58
+ end
59
+
60
+ it "does not return anything when a stub image is assigned" do
61
+ # ActiveRecord does permit square bracket assignment to a column
62
+ # Neo4j does not
63
+ @user[:image] = 'ong.jpg'
64
+ @user.save!
65
+ @user.reload
66
+ expect(@user.image).to be_blank
67
+ end
68
+ end
69
+
70
+ describe "#image" do
71
+ end
72
+
73
+ describe "#save" do
74
+ it "should do nothing when no file has been assigned" do
75
+ expect(@user.save).to be_truthy
76
+ expect(@user.image).to be_blank
77
+ end
78
+
79
+ it "should assign the filename to the database" do
80
+ @user.image = File.open(file_path("ong.jpg"))
81
+ expect(@user.save).to be_truthy
82
+ @user.reload
83
+ # under ActiveRecord these would be equal
84
+ expect(@user[:image]).not_to eq('ong.jpg')
85
+ expect(@user[:image].identifier).to eq('ong.jpg')
86
+ expect(@user.image_identifier).to eq('ong.jpg')
87
+ end
88
+ end
89
+
90
+ describe "#update" do
91
+ it "resets cached value on record reload" do
92
+ @user.image = File.open(file_path("ong.jpg"))
93
+ @user.save!
94
+
95
+ expect(@user.reload.image).to be_present
96
+
97
+ other = User.find(@user.id)
98
+ other.image = nil
99
+ other.save!
100
+
101
+ expect(@user.reload.image).to be_blank
102
+ end
103
+
104
+ it "does not respect `update_column`" do
105
+ @user.image = File.open(file_path("ong.jpg"))
106
+ @user.save!
107
+
108
+ # ActiveRecord would respect `update_column`
109
+ User.find(@user.id).update_column(:image, nil)
110
+
111
+ expect(@user.reload.image).to be_present
112
+ other = User.find(@user.id)
113
+ expect(other.image).to be_present
114
+ end
115
+ end
116
+
117
+ describe "#destroy" do
118
+ end
119
+
120
+ describe "#remote_image_url=" do
121
+ before do
122
+ stub_request(:get, "www.example.com/test.jpg").to_return(body: File.read(file_path("ong.jpg")))
123
+ end
124
+
125
+ it "marks image as changed when setting remote_image_url" do
126
+ expect(@user.image_changed?).to be_falsey
127
+ @user.remote_image_url = 'http://www.example.com/test.jpg'
128
+ expect(@user.image_changed?).to be_truthy
129
+ expect(File.exist?(public_path('uploads/test.jpg'))).to be_falsey
130
+ @user.save!
131
+ @user.reload
132
+ expect(File.exist?(public_path('uploads/test.jpg'))).to be_truthy
133
+ expect(@user.image_changed?).to be_falsey
134
+ end
135
+ end
136
+ end
137
+ end
@@ -12,10 +12,10 @@ class User
12
12
  property :image, type: String
13
13
  end
14
14
 
15
- class DefaultUploader < CarrierWave::Uploader::Base; end
15
+ class DefaultUploader < CarrierWave::Uploader::Base ; end
16
16
 
17
17
  class PngUploader < CarrierWave::Uploader::Base
18
- def extension_white_list
18
+ def extension_whitelist
19
19
  %w(png)
20
20
  end
21
21
  end
@@ -24,14 +24,21 @@ class ProcessingErrorUploader < CarrierWave::Uploader::Base
24
24
  process :end_on_an_era
25
25
 
26
26
  def end_on_an_era
27
- raise CarrierWave::ProcessingError, "Bye Tarja"
27
+ raise CarrierWave::ProcessingError, "Bye OngDB"
28
+ end
29
+ end
30
+
31
+ class DownloadErrorUploader < CarrierWave::Uploader::Base
32
+ def download!(file, headers = {})
33
+ raise CarrierWave::DownloadError
28
34
  end
29
35
  end
30
36
 
31
37
  describe CarrierWave::Neo4j do
32
- let(:user_class) { reset_class }
33
- let(:user_class_png) { reset_class(PngUploader) }
34
- let(:user_class_error) { reset_class(ProcessingErrorUploader) }
38
+ let(:user_class) { reset_class }
39
+ let(:user_class_png) { reset_class(PngUploader) }
40
+ let(:user_class_error) { reset_class(ProcessingErrorUploader) }
41
+ let(:user_download_error) { reset_class(DownloadErrorUploader) }
35
42
  let(:user) { user_class.new }
36
43
 
37
44
  after do
@@ -39,8 +46,8 @@ describe CarrierWave::Neo4j do
39
46
  end
40
47
 
41
48
  describe "#image" do
42
- let(:record) { user_class.new }
43
- subject { record.image }
49
+ let(:user) { user_class.new }
50
+ subject { user.image }
44
51
 
45
52
  context "when nothing is assigned" do
46
53
  it { should be_blank }
@@ -48,9 +55,9 @@ describe CarrierWave::Neo4j do
48
55
 
49
56
  context "when an empty string is assigned" do
50
57
  before do
51
- record.image = ""
52
- record.save
53
- record.reload
58
+ user.image = ""
59
+ user.save
60
+ user.reload
54
61
  end
55
62
 
56
63
  it { should be_blank }
@@ -58,30 +65,61 @@ describe CarrierWave::Neo4j do
58
65
 
59
66
  context "when a filename is stored" do
60
67
  before do
61
- record.image = File.open(file_path("tarja.jpg"))
62
- record.save
63
- record.reload
68
+ user.image = File.open(file_path("ong.jpg"))
69
+ user.save
70
+ user.reload
64
71
  end
65
72
 
66
73
  it { should be_an_instance_of DefaultUploader }
67
- its(:current_path) { should == public_path("uploads/tarja.jpg") }
74
+ its(:current_path) { should == public_path("uploads/ong.jpg") }
75
+ end
76
+
77
+ context "when a model is retrieved from the db" do
78
+ before do
79
+ user.image = File.open(file_path("ong.jpg"))
80
+ user.save
81
+ @found = user_class.find(user.uuid)
82
+ end
83
+
84
+ subject { @found.image }
85
+
86
+ it "has a basic identifier" do
87
+ expect(@found.image_identifier).to eq "ong.jpg"
88
+ end
89
+
90
+ it { should be_an_instance_of DefaultUploader }
91
+ its(:url) { should == "/uploads/ong.jpg"}
92
+ its(:current_path) { should == public_path("uploads/ong.jpg") }
68
93
  end
69
94
  end
70
95
 
71
96
  describe "#save" do
97
+ context "when image= is assigned and the user is saved" do
98
+ let(:user) { user_class.new }
99
+
100
+ before do
101
+ user.image = File.open(file_path("ong.jpg"))
102
+ user.save
103
+ end
104
+
105
+ it "writes the file to disk" do
106
+ expect(File.exist?(public_path('uploads/ong.jpg'))).to be_truthy
107
+ end
108
+ end
109
+
72
110
  context "when remove_image? is true" do
73
- let(:record) { user_class.new }
111
+ let(:user) { user_class.new }
74
112
 
75
113
  before do
76
- record.image = File.open(file_path("tarja.jpg"))
77
- record.save
114
+ user.image = File.open(file_path("ong.jpg"))
115
+ user.save
78
116
 
79
- record.remove_image = true
80
- record.save
81
- record.reload
117
+ user.remove_image = true
118
+ user.save
119
+ user.reload
82
120
  end
83
121
 
84
- subject { record }
122
+ subject { user }
85
123
 
86
124
  its(:image) { should be_blank }
87
125
  end
@@ -89,7 +127,7 @@ describe CarrierWave::Neo4j do
89
127
  context "when validating integrity" do
90
128
  subject do
91
129
  user = user_class_png.new
92
- user.image = File.open(file_path("tarja.jpg"))
130
+ user.image = File.open(file_path("ong.jpg"))
93
131
  user
94
132
  end
95
133
 
@@ -99,7 +137,17 @@ describe CarrierWave::Neo4j do
99
137
  context "when validating processing" do
100
138
  subject do
101
139
  user = user_class_error.new
102
- user.image = File.open(file_path("tarja.jpg"))
140
+ user.image = File.open(file_path("ong.jpg"))
141
+ user
142
+ end
143
+
144
+ it { should_not be_valid }
145
+ end
146
+
147
+ context 'when validating download' do
148
+ subject do
149
+ user = user_download_error.new
150
+ user.remote_image_url = 'http://www.example.com/missing.jpg'
103
151
  user
104
152
  end
105
153
 
@@ -107,18 +155,89 @@ describe CarrierWave::Neo4j do
107
155
  end
108
156
  end
109
157
 
158
+ describe "#update" do
159
+ let(:user) { user_class.new }
160
+
161
+ before do
162
+ user.image = File.open(file_path("ong.jpg"))
163
+ user.save
164
+ end
165
+
166
+ it "does not flag the uploader for removal" do
167
+ user.image = File.open(file_path("neo4j.png"))
168
+ user.save
169
+ expect(user.remove_image?).to be_falsey
170
+ end
171
+
172
+ it "stores the updated file" do
173
+ user.image = File.open(file_path("neo4j.png"))
174
+ user.save
175
+ expect(user.image.current_path).to eq public_path('uploads/neo4j.png')
176
+ expect(user.image.url).to eq '/uploads/neo4j.png'
177
+ end
178
+
179
+ it "writes the updated file to disk" do
180
+ user.image = File.open(file_path("neo4j.png"))
181
+ user.save
182
+ expect(File.exist?(public_path('uploads/neo4j.png'))).to be_truthy
183
+ end
184
+ end
185
+
110
186
  describe "#destroy" do
111
- let(:record) { user_class.new }
187
+ let(:user) { user_class.new }
112
188
 
113
189
  before do
114
- record.image = File.open(file_path("tarja.jpg"))
115
- record.save
190
+ user.image = File.open(file_path("ong.jpg"))
191
+ user.save
116
192
  end
117
193
 
118
194
  it "also destroys the image" do
119
- expect { record.destroy }.to change {
120
- File.exist? public_path("uploads/tarja.jpg")
195
+ file_path = user.image.path
196
+ expect(user.image.current_path).to eq public_path('uploads/ong.jpg')
197
+ expect { user.destroy }.to change {
198
+ File.exist? file_path
121
199
  }.from(true).to(false)
122
200
  end
123
201
  end
202
+
203
+ describe "#reload_from_database" do
204
+ context "when used without mutation" do
205
+ before do
206
+ user.image = File.open(file_path("ong.jpg"))
207
+ user.save
208
+ @reloaded = user.reload_from_database
209
+ end
210
+
211
+ subject { @reloaded.image }
212
+
213
+ it "has an id and image identifier" do
214
+ expect(@reloaded.id).to eq user.id
215
+ expect(@reloaded.image_identifier).to eq "ong.jpg"
216
+ end
217
+
218
+ it { should be_an_instance_of DefaultUploader }
219
+ its(:url) { should == "/uploads/ong.jpg"}
220
+ its(:current_path) { should == public_path("uploads/ong.jpg") }
221
+ end
222
+ end
223
+
224
+ describe "#reload_from_database!" do
225
+ context "when used with mutation" do
226
+ before do
227
+ user.image = File.open(file_path("ong.jpg"))
228
+ user.save
229
+ user.reload_from_database!
230
+ end
231
+
232
+ subject { user.image }
233
+
234
+ it "has an image identifier" do
235
+ expect(user.image_identifier).to eq "ong.jpg"
236
+ end
237
+
238
+ it { should be_an_instance_of DefaultUploader }
239
+ its(:url) { should == "/uploads/ong.jpg"}
240
+ its(:current_path) { should == public_path("uploads/ong.jpg") }
241
+ end
242
+ end
124
243
  end