store_agent 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 +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE +202 -0
- data/README.md +433 -0
- data/Rakefile +2 -0
- data/lib/store_agent.rb +31 -0
- data/lib/store_agent/config.rb +152 -0
- data/lib/store_agent/data_encoder.rb +32 -0
- data/lib/store_agent/data_encoder/gzip_encoder.rb +50 -0
- data/lib/store_agent/data_encoder/openssl_aes_256_cbc_encoder.rb +65 -0
- data/lib/store_agent/exceptions.rb +87 -0
- data/lib/store_agent/node.rb +26 -0
- data/lib/store_agent/node/attachment.rb +93 -0
- data/lib/store_agent/node/attachment/metadata.rb +120 -0
- data/lib/store_agent/node/attachment/permission.rb +121 -0
- data/lib/store_agent/node/object.rb +233 -0
- data/lib/store_agent/node/object/directory_object.rb +264 -0
- data/lib/store_agent/node/object/file_object.rb +197 -0
- data/lib/store_agent/node/object/virtual_object.rb +25 -0
- data/lib/store_agent/node/prepend_module/locker.rb +125 -0
- data/lib/store_agent/node/prepend_module/path_validator.rb +138 -0
- data/lib/store_agent/node/prepend_module/permission_checker.rb +96 -0
- data/lib/store_agent/user.rb +111 -0
- data/lib/store_agent/validator.rb +60 -0
- data/lib/store_agent/version.rb +19 -0
- data/lib/store_agent/version_manager.rb +101 -0
- data/lib/store_agent/version_manager/ruby_git.rb +100 -0
- data/lib/store_agent/version_manager/rugged_git.rb +133 -0
- data/lib/store_agent/workspace.rb +88 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/store_agent/data_encoder/encoder_shared_context.rb +74 -0
- data/spec/store_agent/data_encoder/gzip_encoder_spec.rb +41 -0
- data/spec/store_agent/data_encoder/openssl_aes_256_cbc_encoder_spec.rb +42 -0
- data/spec/store_agent/data_encoder_spec.rb +78 -0
- data/spec/store_agent/node/directory_object_spec.rb +563 -0
- data/spec/store_agent/node/file_object_spec.rb +379 -0
- data/spec/store_agent/node/locker_spec.rb +191 -0
- data/spec/store_agent/node/metadata_spec.rb +339 -0
- data/spec/store_agent/node/object_spec.rb +73 -0
- data/spec/store_agent/node/path_validator_spec.rb +121 -0
- data/spec/store_agent/node/permission_spec.rb +232 -0
- data/spec/store_agent/user_spec.rb +127 -0
- data/spec/store_agent/version_manager/git_shared_context.rb +286 -0
- data/spec/store_agent/version_manager/ruby_git_spec.rb +32 -0
- data/spec/store_agent/version_manager/rugged_git_spec.rb +32 -0
- data/spec/store_agent/workspace_spec.rb +107 -0
- data/spec/store_agent_spec.rb +53 -0
- data/store_agent.gemspec +33 -0
- metadata +252 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require "spec_helper"
|
|
18
|
+
|
|
19
|
+
RSpec.describe StoreAgent::Node::FileObject do
|
|
20
|
+
let :user do
|
|
21
|
+
StoreAgent::User.new("foo", "bar")
|
|
22
|
+
end
|
|
23
|
+
let :workspace do
|
|
24
|
+
user.workspace("test_file_workspace")
|
|
25
|
+
end
|
|
26
|
+
before do
|
|
27
|
+
workspace.create if !workspace.exists?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "ファイル作成のテスト" do
|
|
31
|
+
context "引数が無い場合" do
|
|
32
|
+
it "空のファイルが作成される" do
|
|
33
|
+
workspace.file("foo.txt").create
|
|
34
|
+
expect(workspace.file("foo.txt").read).to eq ""
|
|
35
|
+
expect(workspace.file("foo.txt").file?).to eq true
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
context "引数に文字列を渡す場合" do
|
|
39
|
+
it "ファイルの中身はその文字列になる" do
|
|
40
|
+
workspace.file("bar.txt").create("bar")
|
|
41
|
+
expect(workspace.file("bar.txt").read).to eq "bar"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
context "引数にハッシュを渡す場合" do
|
|
45
|
+
it "body パラメータがファイルの中身になる" do
|
|
46
|
+
workspace.file(".git").create("body" => "hoge")
|
|
47
|
+
expect(workspace.file(".git").read).to eq "hoge"
|
|
48
|
+
end
|
|
49
|
+
it "body パラメータはシンボルでも良い" do
|
|
50
|
+
workspace.file(".keep").create(body: "fuga")
|
|
51
|
+
expect(workspace.file(".keep").read).to eq "fuga"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
context "引数にブロックを渡す場合" do
|
|
55
|
+
it "ファイルの中身は、ブロック内で body に設定した値になる" do
|
|
56
|
+
workspace.file("foobar.txt").create do |f|
|
|
57
|
+
f.body = "foobar"
|
|
58
|
+
end
|
|
59
|
+
expect(workspace.file("foobar.txt").read).to eq "foobar"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
context "作成失敗するケース" do
|
|
63
|
+
it "既に同名のディレクトリがある場合、作成できない" do
|
|
64
|
+
workspace.directory("/foo").create
|
|
65
|
+
expect do
|
|
66
|
+
workspace.file("foo").create
|
|
67
|
+
end.to raise_error
|
|
68
|
+
end
|
|
69
|
+
it "既に同名のファイルがある場合、作成できない" do
|
|
70
|
+
workspace.file("hogefuga.txt").create
|
|
71
|
+
expect do
|
|
72
|
+
workspace.directory("hogefuga.txt").create
|
|
73
|
+
end.to raise_error
|
|
74
|
+
end
|
|
75
|
+
it "ファイル名がメタデータの拡張子で終わる場合、作成できない" do
|
|
76
|
+
expect do
|
|
77
|
+
workspace.file("hoge.meta").create
|
|
78
|
+
end.to raise_error
|
|
79
|
+
end
|
|
80
|
+
it "ファイル名がパーミッションデータの拡張子で終わる場合、作成できない" do
|
|
81
|
+
expect do
|
|
82
|
+
workspace.file("hoge.perm").create
|
|
83
|
+
end.to raise_error
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "ファイル更新のテスト" do
|
|
89
|
+
before do
|
|
90
|
+
file = workspace.file("update_test.txt")
|
|
91
|
+
if !file.exists?
|
|
92
|
+
file.create("1234567890")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "引数が無い場合" do
|
|
97
|
+
it "エラーになる" do
|
|
98
|
+
expect do
|
|
99
|
+
workspace.file("update_test.txt").update
|
|
100
|
+
end.to raise_error
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
context "引数に文字列を渡す場合" do
|
|
104
|
+
it "ファイルの中身はその文字列になる" do
|
|
105
|
+
workspace.file("update_test.txt").update("update_01")
|
|
106
|
+
expect(workspace.file("update_test.txt").read).to eq "update_01"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
context "引数にハッシュを渡す場合" do
|
|
110
|
+
it "body パラメータがファイルの中身になる" do
|
|
111
|
+
workspace.file("update_test.txt").update("update_02")
|
|
112
|
+
expect(workspace.file("update_test.txt").read).to eq "update_02"
|
|
113
|
+
end
|
|
114
|
+
it "body パラメータはシンボルでも良い" do
|
|
115
|
+
workspace.file("update_test.txt").update("update_03")
|
|
116
|
+
expect(workspace.file("update_test.txt").read).to eq "update_03"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
context "引数にブロックを渡す場合" do
|
|
120
|
+
it "ファイルの中身は、ブロック内で body に設定した値になる" do
|
|
121
|
+
workspace.file("update_test.txt").update do |f|
|
|
122
|
+
f.body = "update_04"
|
|
123
|
+
end
|
|
124
|
+
expect(workspace.file("update_test.txt").read).to eq "update_04"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
context "ファイル削除のテスト" do
|
|
130
|
+
before do
|
|
131
|
+
file = workspace.file("delete_test.txt")
|
|
132
|
+
if !file.exists?
|
|
133
|
+
file.create
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
context "削除権限がある場合" do
|
|
138
|
+
before do
|
|
139
|
+
workspace.file("delete_test.txt").delete
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "ファイルが削除される" do
|
|
143
|
+
expect(workspace.file("delete_test.txt").exists?).to be false
|
|
144
|
+
end
|
|
145
|
+
it "メタデータファイルが削除される" do
|
|
146
|
+
expect(File.exists?(workspace.file("delete_test.txt").metadata.file_path)).to be false
|
|
147
|
+
end
|
|
148
|
+
it "パーミッションファイルが削除される" do
|
|
149
|
+
expect(File.exists?(workspace.file("delete_test.txt").permission.file_path)).to be false
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
context "削除権限が無い場合" do
|
|
153
|
+
before do
|
|
154
|
+
begin
|
|
155
|
+
StoreAgent::User.new.workspace("test_file_workspace").file("delete_test.txt").delete
|
|
156
|
+
rescue
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "ファイルは削除されない" do
|
|
161
|
+
expect(workspace.file("delete_test.txt").exists?).to be true
|
|
162
|
+
end
|
|
163
|
+
it "メタデータファイルは削除されない" do
|
|
164
|
+
end
|
|
165
|
+
it "パーミッションファイルは削除されない" do
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context "メタデータ取得のテスト" do
|
|
171
|
+
it "get_metadata でメタデータをハッシュ形式で取得できる" do
|
|
172
|
+
workspace.file("get_metadata.txt").create
|
|
173
|
+
expect(workspace.file("get_metadata.txt").get_metadata.class).to eq Hash
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context "パーミッション情報取得のテスト" do
|
|
178
|
+
it "get_permissions でパーミッション情報をハッシュ形式で取得できる" do
|
|
179
|
+
workspace.file("get_permissions.txt").create
|
|
180
|
+
expect(workspace.file("get_permissions.txt").get_permissions.class).to eq Hash
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
context "オーナー変更のテスト" do
|
|
185
|
+
before do
|
|
186
|
+
if !(file = workspace.file("chown.txt")).exists?
|
|
187
|
+
file.create
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
it "userは権限がないので、オーナー変更できない" do
|
|
191
|
+
expect do
|
|
192
|
+
workspace.file("chown.txt").chown(identifier: "hoge")
|
|
193
|
+
end.to raise_error
|
|
194
|
+
end
|
|
195
|
+
it "superuserはオーナー変更できる" do
|
|
196
|
+
superuser = StoreAgent::Superuser.new
|
|
197
|
+
superuser.workspace("test_file_workspace").file("chown.txt").chown(identifier: "hoge")
|
|
198
|
+
expect(workspace.file("chown.txt").metadata["owner"]).to eq "hoge"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
context "配下オブジェクトを取得しようとする" do
|
|
203
|
+
let :file do
|
|
204
|
+
workspace.file("search_children.txt")
|
|
205
|
+
end
|
|
206
|
+
before do
|
|
207
|
+
if !file.exists?
|
|
208
|
+
file.create
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "ディレクトリを取得しようとするとエラーになる" do
|
|
213
|
+
expect do
|
|
214
|
+
file.directory("hoge")
|
|
215
|
+
end.to raise_error
|
|
216
|
+
end
|
|
217
|
+
it "ファイルを取得しようとするとエラーになる" do
|
|
218
|
+
expect do
|
|
219
|
+
file.file("hoge.txt")
|
|
220
|
+
end.to raise_error
|
|
221
|
+
end
|
|
222
|
+
it "タイプが不明なオブジェクトを取得しようとするとエラーになる" do
|
|
223
|
+
expect do
|
|
224
|
+
file.find_object("hoge")
|
|
225
|
+
end.to raise_error
|
|
226
|
+
end
|
|
227
|
+
it "直下のファイル一覧を取得しようとすると、空の配列が返ってくる" do
|
|
228
|
+
expect(file.children).to eq []
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context "ファイルのコピー" do
|
|
233
|
+
let :directory do
|
|
234
|
+
workspace.directory("copy")
|
|
235
|
+
end
|
|
236
|
+
let :src_file do
|
|
237
|
+
workspace.file("copy/src.txt")
|
|
238
|
+
end
|
|
239
|
+
before do
|
|
240
|
+
if !directory.exists?
|
|
241
|
+
directory.create
|
|
242
|
+
src_file.create("copy")
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
context "コピー先にオブジェクトが無い場合" do
|
|
247
|
+
it "コピー先にファイルが作成され、メタデータが更新される" do
|
|
248
|
+
dest_create_path = "copy/dest_create.txt"
|
|
249
|
+
|
|
250
|
+
prev_count = workspace.directory("copy").directory_file_count
|
|
251
|
+
src_file.copy(dest_create_path)
|
|
252
|
+
expect(workspace.file(dest_create_path).read).to eq "copy"
|
|
253
|
+
expect(workspace.directory("copy").directory_file_count).to eq prev_count + 1
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
context "コピー先にファイルが存在する場合" do
|
|
257
|
+
it "コピー先のファイルが上書きされ、メタデータが更新される" do
|
|
258
|
+
dest_update_path = "copy/dest_update.txt"
|
|
259
|
+
workspace.file(dest_update_path).create("dest update file")
|
|
260
|
+
|
|
261
|
+
prev_count = workspace.directory("copy").directory_file_count
|
|
262
|
+
prev_bytesize = workspace.file(dest_update_path).metadata["bytes"]
|
|
263
|
+
src_file.copy(dest_update_path)
|
|
264
|
+
expect(workspace.file(dest_update_path).read).to eq "copy"
|
|
265
|
+
expect(workspace.file(dest_update_path).metadata["bytes"]).to eq 4
|
|
266
|
+
expect(workspace.directory("copy").directory_file_count).to eq prev_count
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
context "コピー先にディレクトリが存在する場合" do
|
|
270
|
+
it "コピー先のディレクトリ内に同名のオブジェクトが存在しない場合、ファイルが作成される" do
|
|
271
|
+
dest_directory_path = "copy/dest_dir"
|
|
272
|
+
workspace.directory(dest_directory_path).create
|
|
273
|
+
|
|
274
|
+
prev_count = workspace.directory(dest_directory_path).directory_file_count
|
|
275
|
+
prev_bytesize = workspace.directory(dest_directory_path).metadata["directory_bytes"]
|
|
276
|
+
src_file.copy(dest_directory_path)
|
|
277
|
+
expect(workspace.directory(dest_directory_path).file("src.txt").read).to eq "copy"
|
|
278
|
+
expect(workspace.directory(dest_directory_path).metadata["directory_bytes"]).to eq prev_bytesize + 4
|
|
279
|
+
expect(workspace.directory(dest_directory_path).directory_file_count).to eq prev_count + 1
|
|
280
|
+
end
|
|
281
|
+
it "コピー先のディレクトリ内に同名のファイルが存在する場合、そのファイルが上書きされる" do
|
|
282
|
+
dest_directory_path = "copy/dest_exists_file"
|
|
283
|
+
workspace.directory(dest_directory_path).create
|
|
284
|
+
workspace.directory(dest_directory_path).file("src.txt").create("file already exists")
|
|
285
|
+
|
|
286
|
+
prev_count = workspace.directory(dest_directory_path).directory_file_count
|
|
287
|
+
prev_bytesize = workspace.directory(dest_directory_path).metadata["directory_bytes"]
|
|
288
|
+
src_file.copy(dest_directory_path)
|
|
289
|
+
expect(workspace.directory(dest_directory_path).file("src.txt").read).to eq "copy"
|
|
290
|
+
expect(workspace.directory(dest_directory_path).metadata["directory_bytes"]).to eq prev_bytesize - 15
|
|
291
|
+
expect(workspace.directory(dest_directory_path).directory_file_count).to eq prev_count
|
|
292
|
+
end
|
|
293
|
+
it "コピー先のディレクトリ内に同名のディレクトリが存在する場合、例外が発生する" do
|
|
294
|
+
dest_directory_path = "copy/dest_exists_dir"
|
|
295
|
+
workspace.directory(dest_directory_path).create
|
|
296
|
+
workspace.directory(dest_directory_path).directory("src.txt").create
|
|
297
|
+
|
|
298
|
+
expect do
|
|
299
|
+
src_file.copy(dest_directory_path)
|
|
300
|
+
end.to raise_error StoreAgent::InvalidNodeTypeError
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context "ファイルの移動" do
|
|
306
|
+
let :directory do
|
|
307
|
+
workspace.directory("move")
|
|
308
|
+
end
|
|
309
|
+
let :src_file do
|
|
310
|
+
workspace.file("move/src.txt")
|
|
311
|
+
end
|
|
312
|
+
before do
|
|
313
|
+
if !directory.exists?
|
|
314
|
+
directory.create
|
|
315
|
+
end
|
|
316
|
+
if !src_file.exists?
|
|
317
|
+
src_file.create("move")
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
context "移動先にオブジェクトが無い場合" do
|
|
322
|
+
it "移動先にファイルが作成され、メタデータが更新される" do
|
|
323
|
+
dest_create_path = "move/dest_create.txt"
|
|
324
|
+
prev_count = workspace.directory("move").directory_file_count
|
|
325
|
+
prev_bytesize = workspace.directory("move").metadata["bytes"]
|
|
326
|
+
src_file.move(dest_create_path)
|
|
327
|
+
expect(workspace.file(dest_create_path).read).to eq "move"
|
|
328
|
+
expect(workspace.directory("move").metadata["bytes"]).to eq prev_bytesize
|
|
329
|
+
expect(workspace.directory("move").directory_file_count).to eq prev_count
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
context "移動先にファイルが存在する場合" do
|
|
333
|
+
it "移動先のファイルが上書きされ、メタデータが更新される" do
|
|
334
|
+
dest_update_path = "move/dest_update.txt"
|
|
335
|
+
workspace.file(dest_update_path).create("dest update file")
|
|
336
|
+
prev_count = workspace.directory("move").directory_file_count
|
|
337
|
+
prev_bytesize = workspace.file(dest_update_path).metadata["bytes"]
|
|
338
|
+
src_file.move(dest_update_path)
|
|
339
|
+
expect(workspace.file(dest_update_path).read).to eq "move"
|
|
340
|
+
expect(workspace.file(dest_update_path).metadata["bytes"]).to eq 4
|
|
341
|
+
expect(workspace.directory("move").directory_file_count).to eq prev_count - 1
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
context "移動先にディレクトリが存在する場合" do
|
|
345
|
+
it "移動先のディレクトリ内に同名のオブジェクトが存在しない場合、ファイルが作成される" do
|
|
346
|
+
dest_directory_path = "move/dest_dir"
|
|
347
|
+
workspace.directory(dest_directory_path).create
|
|
348
|
+
|
|
349
|
+
prev_count = workspace.directory(dest_directory_path).directory_file_count
|
|
350
|
+
prev_bytesize = workspace.directory(dest_directory_path).metadata["directory_bytes"]
|
|
351
|
+
src_file.move(dest_directory_path)
|
|
352
|
+
expect(workspace.directory(dest_directory_path).file("src.txt").read).to eq "move"
|
|
353
|
+
expect(workspace.directory(dest_directory_path).metadata["directory_bytes"]).to eq prev_bytesize + 4
|
|
354
|
+
expect(workspace.directory(dest_directory_path).directory_file_count).to eq prev_count + 1
|
|
355
|
+
end
|
|
356
|
+
it "移動先のディレクトリ内に同名のファイルが存在する場合、そのファイルが上書きされる" do
|
|
357
|
+
dest_directory_path = "move/dest_exists_file"
|
|
358
|
+
workspace.directory(dest_directory_path).create
|
|
359
|
+
workspace.directory(dest_directory_path).file("src.txt").create("file already exists")
|
|
360
|
+
|
|
361
|
+
prev_count = workspace.directory(dest_directory_path).directory_file_count
|
|
362
|
+
prev_bytesize = workspace.directory(dest_directory_path).metadata["directory_bytes"]
|
|
363
|
+
src_file.move(dest_directory_path)
|
|
364
|
+
expect(workspace.directory(dest_directory_path).file("src.txt").read).to eq "move"
|
|
365
|
+
expect(workspace.directory(dest_directory_path).metadata["directory_bytes"]).to eq prev_bytesize - 15
|
|
366
|
+
expect(workspace.directory(dest_directory_path).directory_file_count).to eq prev_count
|
|
367
|
+
end
|
|
368
|
+
it "移動先のディレクトリ内に同名のディレクトリが存在する場合、例外が発生する" do
|
|
369
|
+
dest_directory_path = "move/dest_exists_dir"
|
|
370
|
+
workspace.directory(dest_directory_path).create
|
|
371
|
+
workspace.directory(dest_directory_path).directory("src.txt").create
|
|
372
|
+
|
|
373
|
+
expect do
|
|
374
|
+
src_file.move(dest_directory_path)
|
|
375
|
+
end.to raise_error StoreAgent::InvalidNodeTypeError
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright 2015 realglobe, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#++
|
|
16
|
+
|
|
17
|
+
require "spec_helper"
|
|
18
|
+
|
|
19
|
+
RSpec.describe StoreAgent::Node::Locker do
|
|
20
|
+
let :user do
|
|
21
|
+
StoreAgent::User.new("foo")
|
|
22
|
+
end
|
|
23
|
+
let :workspace do
|
|
24
|
+
user.workspace("test_lock")
|
|
25
|
+
end
|
|
26
|
+
before do
|
|
27
|
+
skip "時間かかるのでスキップ"
|
|
28
|
+
end
|
|
29
|
+
before :all do
|
|
30
|
+
workspace = StoreAgent::User.new("foo").workspace("test_lock")
|
|
31
|
+
workspace.create
|
|
32
|
+
workspace.directory("create").create
|
|
33
|
+
workspace.directory("read").create
|
|
34
|
+
workspace.file("read/foo.txt").create("foo")
|
|
35
|
+
workspace.directory("update").create
|
|
36
|
+
workspace.file("update/bar.txt").create{|f| f.body = "bar"}
|
|
37
|
+
workspace.directory("delete").create
|
|
38
|
+
workspace.file("delete/hoge.txt").create(:hoge)
|
|
39
|
+
workspace.file("delete/fuga.txt").create(:fuga)
|
|
40
|
+
|
|
41
|
+
class StoreAgent::Node::Object
|
|
42
|
+
prepend Module.new {
|
|
43
|
+
def test_sleep
|
|
44
|
+
sleep 0.2
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def create(*)
|
|
48
|
+
super do
|
|
49
|
+
test_sleep
|
|
50
|
+
yield
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
def read(*)
|
|
54
|
+
super do
|
|
55
|
+
test_sleep
|
|
56
|
+
yield
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
def update(*)
|
|
60
|
+
super do
|
|
61
|
+
test_sleep
|
|
62
|
+
yield
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
def delete(*)
|
|
66
|
+
super do
|
|
67
|
+
test_sleep
|
|
68
|
+
yield
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
after :all do
|
|
75
|
+
class StoreAgent::Node::Object
|
|
76
|
+
prepend Module.new {
|
|
77
|
+
def test_sleep
|
|
78
|
+
end
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "オブジェクトcreate時のロック" do
|
|
84
|
+
it "作成中のオブジェクトは排他ロックされている" do
|
|
85
|
+
Process.fork do
|
|
86
|
+
workspace.directory("create/dir").create
|
|
87
|
+
end
|
|
88
|
+
sleep 0.1
|
|
89
|
+
response = true
|
|
90
|
+
open(workspace.directory("create/dir").send(:lock_file_path)) do |f|
|
|
91
|
+
response = f.flock File::LOCK_SH | File::LOCK_NB
|
|
92
|
+
end
|
|
93
|
+
Process.waitall
|
|
94
|
+
expect(response).to be false
|
|
95
|
+
end
|
|
96
|
+
it "作成中のオブジェクトの親ディレクトリは排他ロックされている" do
|
|
97
|
+
Process.fork do
|
|
98
|
+
workspace.file("create/file.txt").create
|
|
99
|
+
end
|
|
100
|
+
sleep 0.1
|
|
101
|
+
response = true
|
|
102
|
+
open(workspace.directory("create").send(:lock_file_path)) do |f|
|
|
103
|
+
response = f.flock File::LOCK_SH | File::LOCK_NB
|
|
104
|
+
end
|
|
105
|
+
Process.waitall
|
|
106
|
+
expect(response).to be false
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context "オブジェクトread時のロック" do
|
|
111
|
+
it "読み込み中のオブジェクトは共有ロックされている" do
|
|
112
|
+
Process.fork do
|
|
113
|
+
workspace.file("read/foo.txt").read
|
|
114
|
+
end
|
|
115
|
+
sleep 0.1
|
|
116
|
+
response = true
|
|
117
|
+
open(workspace.file("read/foo.txt").send(:lock_file_path)) do |f|
|
|
118
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
119
|
+
end
|
|
120
|
+
Process.waitall
|
|
121
|
+
expect(response).to be false
|
|
122
|
+
expect(workspace.file("read/foo.txt").read).to eq "foo"
|
|
123
|
+
end
|
|
124
|
+
it "読み込み中のオブジェクトの親ディレクトリは共有ロックされている" do
|
|
125
|
+
Process.fork do
|
|
126
|
+
workspace.file("read/foo.txt").read
|
|
127
|
+
end
|
|
128
|
+
sleep 0.1
|
|
129
|
+
response = true
|
|
130
|
+
open(workspace.directory("read").send(:lock_file_path)) do |f|
|
|
131
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
132
|
+
end
|
|
133
|
+
Process.waitall
|
|
134
|
+
expect(response).to be false
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
context "オブジェクトupdate時のロック" do
|
|
139
|
+
it "更新中のオブジェクトは排他ロックされている" do
|
|
140
|
+
Process.fork do
|
|
141
|
+
workspace.file("update/bar.txt").update("test")
|
|
142
|
+
end
|
|
143
|
+
sleep 0.1
|
|
144
|
+
response = true
|
|
145
|
+
open(workspace.file("update/bar.txt").send(:lock_file_path)) do |f|
|
|
146
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
147
|
+
end
|
|
148
|
+
Process.waitall
|
|
149
|
+
expect(response).to be false
|
|
150
|
+
end
|
|
151
|
+
it "更新中のオブジェクトの親ディレクトリは排他ロックされている" do
|
|
152
|
+
Process.fork do
|
|
153
|
+
workspace.file("update/bar.txt").update("test")
|
|
154
|
+
end
|
|
155
|
+
sleep 0.1
|
|
156
|
+
response = true
|
|
157
|
+
open(workspace.directory("update").send(:lock_file_path)) do |f|
|
|
158
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
159
|
+
end
|
|
160
|
+
Process.waitall
|
|
161
|
+
expect(response).to be false
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context "オブジェクトdelete時のロック" do
|
|
166
|
+
it "削除中のオブジェクトは排他ロックされている" do
|
|
167
|
+
Process.fork do
|
|
168
|
+
workspace.file("delete/hoge.txt").delete
|
|
169
|
+
end
|
|
170
|
+
sleep 0.1
|
|
171
|
+
response = true
|
|
172
|
+
open(workspace.file("delete/hoge.txt").send(:lock_file_path)) do |f|
|
|
173
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
174
|
+
end
|
|
175
|
+
Process.waitall
|
|
176
|
+
expect(response).to be false
|
|
177
|
+
end
|
|
178
|
+
it "削除中のオブジェクトの親ディレクトリは排他ロックされている" do
|
|
179
|
+
Process.fork do
|
|
180
|
+
workspace.file("delete/fuga.txt").delete
|
|
181
|
+
end
|
|
182
|
+
sleep 0.1
|
|
183
|
+
response = true
|
|
184
|
+
open(workspace.directory("delete").send(:lock_file_path)) do |f|
|
|
185
|
+
response = f.flock File::LOCK_EX | File::LOCK_NB
|
|
186
|
+
end
|
|
187
|
+
Process.waitall
|
|
188
|
+
expect(response).to be false
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|