carrierwave-neo4j 2.0.0 → 3.0.0

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.
@@ -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