moped-gridfs 1.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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +90 -0
- data/Rakefile +6 -0
- data/gemfiles/moped15.gemfile +4 -0
- data/lib/moped/gridfs.rb +2 -0
- data/lib/moped/gridfs/access_modes.rb +48 -0
- data/lib/moped/gridfs/bucket.rb +66 -0
- data/lib/moped/gridfs/bucketable.rb +33 -0
- data/lib/moped/gridfs/buckets.rb +37 -0
- data/lib/moped/gridfs/extensions/session.rb +21 -0
- data/lib/moped/gridfs/file.rb +233 -0
- data/lib/moped/gridfs/files.rb +29 -0
- data/lib/moped/gridfs/inspectable.rb +15 -0
- data/lib/moped/gridfs/version.rb +5 -0
- data/moped-gridfs.gemspec +26 -0
- data/perf/compare.rb +143 -0
- data/perf/perf_helper.rb +33 -0
- data/spec/lib/moped/gridfs/bucket_spec.rb +119 -0
- data/spec/lib/moped/gridfs/buckets_spec.rb +45 -0
- data/spec/lib/moped/gridfs/file_spec.rb +83 -0
- data/spec/lib/moped/gridfs/getters.rb +78 -0
- data/spec/lib/moped/gridfs/read.rb +106 -0
- data/spec/lib/moped/gridfs/setters.rb +113 -0
- data/spec/lib/moped/gridfs/write.rb +152 -0
- data/spec/spec_helper.rb +33 -0
- metadata +152 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples :getters do
|
4
|
+
|
5
|
+
before do
|
6
|
+
file = bucket.open("file", "w")
|
7
|
+
file.write("foobar")
|
8
|
+
file.metadata = {pdf: true}
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:file) { bucket.open("file", access_mode) }
|
12
|
+
|
13
|
+
let(:truncate_mode) { file.__send__(:truncate?) }
|
14
|
+
|
15
|
+
describe '#length' do
|
16
|
+
|
17
|
+
it 'returns the file length' do
|
18
|
+
expect(file.length).to eq(truncate_mode ? 0 : 6)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#content_type' do
|
23
|
+
|
24
|
+
it 'returns the contentType value' do
|
25
|
+
expect(file.content_type).to eq('application/octet-stream')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#chunk_size' do
|
30
|
+
|
31
|
+
it 'returns the file chunk size' do
|
32
|
+
expect(file.chunk_size).to eq(file.default_chunk_size)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#filename' do
|
37
|
+
|
38
|
+
it 'returns the file chunk size' do
|
39
|
+
expect(file.filename).to eq("file")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#md5' do
|
44
|
+
|
45
|
+
it 'returns the file chunk size' do
|
46
|
+
expected = Digest::MD5.hexdigest("foobar")
|
47
|
+
expect(file.md5).to eq(truncate_mode ? nil : expected)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#metadata' do
|
52
|
+
it 'returns the file metadata' do
|
53
|
+
expected = {'pdf' => true}
|
54
|
+
expect(file.metadata).to eq(truncate_mode ? Hash.new : expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#contentType' do
|
59
|
+
|
60
|
+
it 'is not defined' do
|
61
|
+
expect(file).not_to respond_to(:contentType)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#chunkSize' do
|
66
|
+
|
67
|
+
it 'is not defined' do
|
68
|
+
expect(file).not_to respond_to(:chunkSize)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#uploadDate' do
|
73
|
+
|
74
|
+
it 'is not defined' do
|
75
|
+
expect(file).not_to respond_to(:uploadDate)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples :read do
|
4
|
+
|
5
|
+
context '#read' do
|
6
|
+
|
7
|
+
context 'when the file is empty' do
|
8
|
+
|
9
|
+
before do
|
10
|
+
bucket.open("file", "w").write('')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns an empty string' do
|
14
|
+
expect(bucket.open("file", access_mode).read).to eq('')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
["a", "\xE9a", "a"*($chunk_size-1), "a"*$chunk_size, "a"*($chunk_size)+"b"].each do |buffer|
|
19
|
+
|
20
|
+
before { buffer.force_encoding('BINARY') }
|
21
|
+
|
22
|
+
context "given a file #{buffer.size}-byte(s) long" do
|
23
|
+
|
24
|
+
let!(:file) do
|
25
|
+
bucket.open("file", "w").write(buffer)
|
26
|
+
file = bucket.open("file", access_mode)
|
27
|
+
file.rewind if file.append?
|
28
|
+
file
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'changes the position' do
|
32
|
+
(1..buffer.size).to_a.concat([buffer.size*2]) do |i|
|
33
|
+
file.rewind
|
34
|
+
expect(file.read(i)).to eq(buffer[0..i - 1])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when called without args" do
|
39
|
+
|
40
|
+
it 'returns the whole file content' do
|
41
|
+
expect(file.read).to eq(buffer)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when called multiple times to read some bytes each time" do
|
46
|
+
|
47
|
+
it 'returns the expected data' do
|
48
|
+
data = []
|
49
|
+
data << file.read(1) until file.eof?
|
50
|
+
expect(data.size).to eq(buffer.size)
|
51
|
+
expect(data.join).to eq(buffer)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'changes the position' do
|
55
|
+
readed = 0
|
56
|
+
steps = []
|
57
|
+
2.times { steps << buffer.size / 2 }
|
58
|
+
steps << buffer.size % 2
|
59
|
+
|
60
|
+
steps.each_with_index do |size, index|
|
61
|
+
file.read(size)
|
62
|
+
expect(file.pos).to eq(readed += size)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when zero is passed' do
|
68
|
+
|
69
|
+
it 'returns an empty string' do
|
70
|
+
expect(file.read(0)).to eq('')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'does not change the position' do
|
74
|
+
file.read(0)
|
75
|
+
expect(file.pos).to be_zero
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when a negative number is passed' do
|
80
|
+
|
81
|
+
before { file.read(1) }
|
82
|
+
|
83
|
+
it 'raises an error' do
|
84
|
+
expect { file.read(-1) }.to raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'does not change the position' do
|
88
|
+
expect(file.pos).to eq(1)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "when an integer is passed" do
|
93
|
+
|
94
|
+
it 'returns the content of the file up to the given position' do
|
95
|
+
expect(file.read(buffer.size * 2)).to eq(buffer)
|
96
|
+
|
97
|
+
(1..buffer.size).to_a do |i|
|
98
|
+
file.rewind
|
99
|
+
expect(file.read(i)).to eq(buffer[0..i - 1])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples :setters do
|
4
|
+
|
5
|
+
before do
|
6
|
+
file = bucket.open("file", "w")
|
7
|
+
file.write("foobar")
|
8
|
+
file.metadata = {pdf: true}
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:file) { bucket.open("file", access_mode) }
|
12
|
+
|
13
|
+
let(:truncate_mode) { file.__send__(:truncate?) }
|
14
|
+
|
15
|
+
describe '#length=' do
|
16
|
+
|
17
|
+
it 'is not defined' do
|
18
|
+
expect(file).not_to respond_to(:length=)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#content_type=' do
|
23
|
+
|
24
|
+
before { file.content_type = "foo" }
|
25
|
+
|
26
|
+
it 'changes the contentType attribute in memory' do
|
27
|
+
expect(file.content_type).to eq("foo")
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'changes the contentType attribute on disk' do
|
31
|
+
expect(bucket.open("file", "r").content_type).to eq("foo")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#contentType=' do
|
36
|
+
|
37
|
+
it 'is not defined' do
|
38
|
+
expect(file).not_to respond_to(:contentType=)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#chunk_size=' do
|
43
|
+
|
44
|
+
it 'is not defined' do
|
45
|
+
expect(file).not_to respond_to(:chunk_size=)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#chunkSize=' do
|
50
|
+
|
51
|
+
it 'is not defined' do
|
52
|
+
expect(file).not_to respond_to(:chunkSize=)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#filename=' do
|
57
|
+
|
58
|
+
before { file.filename = "foo" }
|
59
|
+
|
60
|
+
it 'changes the contentType attribute in memory' do
|
61
|
+
expect(file.filename).to eq("foo")
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'changes the contentType attribute on disk' do
|
65
|
+
expect { bucket.open("foo", "r") }.not_to raise_error
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#md5=' do
|
70
|
+
|
71
|
+
it 'is not defined' do
|
72
|
+
expect(file).not_to respond_to(:md5=)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
describe '#metadata=' do
|
78
|
+
|
79
|
+
let(:metadata) { {key: 'value'} }
|
80
|
+
|
81
|
+
before { file.metadata = metadata }
|
82
|
+
|
83
|
+
it 'changes the contentType attribute in memory' do
|
84
|
+
expect(file.metadata).to eq(metadata)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'changes the contentType attribute on disk' do
|
88
|
+
expect(bucket.open("file", "r").metadata).to eq('key' => 'value')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#uploadDate=' do
|
93
|
+
|
94
|
+
it 'is not defined' do
|
95
|
+
expect(file).not_to respond_to(:uploadDate=)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#upload_date=' do
|
100
|
+
|
101
|
+
let(:now) { Time.new(2013,01,01).utc }
|
102
|
+
|
103
|
+
before { file.upload_date = now }
|
104
|
+
|
105
|
+
it 'changes the contentType attribute in memory' do
|
106
|
+
expect(file.upload_date).to eq(now)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'changes the contentType attribute on disk' do
|
110
|
+
expect(bucket.open("file", "r").upload_date).to eq(now)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples :write do
|
4
|
+
|
5
|
+
describe '#write' do
|
6
|
+
["a", "\xE9a", "a"*($chunk_size-1), "a"*$chunk_size, "a"*($chunk_size)+"b"].each do |buffer|
|
7
|
+
|
8
|
+
before { buffer.force_encoding('BINARY') }
|
9
|
+
|
10
|
+
pos1 = buffer.size + rand(1..$chunk_size*2)
|
11
|
+
|
12
|
+
pos2 = rand(0..buffer.size-1)
|
13
|
+
|
14
|
+
context "given a #{buffer.size}-byte(s) long buffer" do
|
15
|
+
|
16
|
+
context "when start from a position greater (#{pos1}) than the file length" do
|
17
|
+
|
18
|
+
let(:file) { bucket.open("file", access_mode) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
file.write(buffer)
|
22
|
+
file.seek(pos1)
|
23
|
+
file.write(buffer)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'writes the data' do
|
27
|
+
expect(bucket.open("file", "r").read).to eq(buffer * 2)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'updates the length' do
|
31
|
+
expect(file.length).to eq(buffer.size * 2)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'updates the position' do
|
35
|
+
expect(file.pos).to eq(buffer.size * 2)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'updates the md5' do
|
39
|
+
expect(file.md5).to eq(Digest::MD5.hexdigest(buffer+buffer))
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'writes the length attributes' do
|
43
|
+
expect(bucket.open("file", "r").length).to eq(buffer.size * 2)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when start from a position (#{pos2}) lesser than the file length" do
|
48
|
+
|
49
|
+
let(:file) { bucket.open("file", access_mode) }
|
50
|
+
|
51
|
+
let(:buffer2) { 'data' }
|
52
|
+
|
53
|
+
before do
|
54
|
+
file.write(buffer)
|
55
|
+
file.seek(pos2)
|
56
|
+
file.write(buffer2)
|
57
|
+
end
|
58
|
+
|
59
|
+
let(:expected) do
|
60
|
+
if file.append?
|
61
|
+
buffer + buffer2
|
62
|
+
else
|
63
|
+
s = buffer2.size
|
64
|
+
pos2.zero? ? "#{buffer2}#{buffer[s..-1]}" : "#{buffer[0..pos2-1]}#{buffer2}#{buffer[pos2+s..-1]}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'write the data' do
|
69
|
+
expect(bucket.open("file", "r").read).to eq(expected)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'updates the length' do
|
73
|
+
expect(file.length).to eq(expected.size)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'updates the position' do
|
77
|
+
expected_pos = file.append? ? buffer.size + buffer2.size : pos2 + buffer2.size
|
78
|
+
expect(file.pos).to eq(expected_pos)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'updates the md5' do
|
82
|
+
expect(file.md5).to eq(Digest::MD5.hexdigest(expected))
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'writes the length attributes' do
|
86
|
+
expect(bucket.open("file", "r").length).to eq(expected.size)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when start from a non-zero position' do
|
91
|
+
|
92
|
+
let(:file) { bucket.open("file", access_mode) }
|
93
|
+
|
94
|
+
before do
|
95
|
+
file.seek($chunk_size * 3)
|
96
|
+
file.write(buffer)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'writes from the start' do
|
100
|
+
expect(bucket.open("file", "r").read).to eq(buffer)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'updates the length' do
|
104
|
+
expect(file.length).to eq(buffer.size)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'updates the position' do
|
108
|
+
expect(file.pos).to eq(buffer.size)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'updates the md5' do
|
112
|
+
expect(file.md5).to eq(Digest::MD5.hexdigest(buffer))
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'writes the length attributes' do
|
116
|
+
expect(bucket.open("file", "r").length).to eq(buffer.size)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
(1..5).each do |n|
|
121
|
+
context "when is written #{n} times" do
|
122
|
+
let(:file) { bucket.open("file", access_mode) }
|
123
|
+
|
124
|
+
before do
|
125
|
+
n.times { file.write(buffer) }
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'writes the data' do
|
129
|
+
expect(bucket.open("file", "r").read).to eq(buffer*n)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'writes the length attributes' do
|
133
|
+
expect(bucket.open("file", "r").length).to eq(buffer.size*n)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'updates the md5' do
|
137
|
+
expect(file.md5).to eq(Digest::MD5.hexdigest(buffer*n))
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'updates the length' do
|
141
|
+
expect(file.length).to eq(buffer.size*n)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'updates the position' do
|
145
|
+
expect(file.pos).to eq(buffer.size*n)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|