rims 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/ChangeLog +379 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +566 -0
  7. data/Rakefile +29 -0
  8. data/bin/rims +11 -0
  9. data/lib/rims.rb +45 -0
  10. data/lib/rims/auth.rb +133 -0
  11. data/lib/rims/cksum_kvs.rb +68 -0
  12. data/lib/rims/cmd.rb +809 -0
  13. data/lib/rims/daemon.rb +338 -0
  14. data/lib/rims/db.rb +793 -0
  15. data/lib/rims/error.rb +23 -0
  16. data/lib/rims/gdbm_kvs.rb +76 -0
  17. data/lib/rims/hash_kvs.rb +66 -0
  18. data/lib/rims/kvs.rb +101 -0
  19. data/lib/rims/lock.rb +151 -0
  20. data/lib/rims/mail_store.rb +663 -0
  21. data/lib/rims/passwd.rb +251 -0
  22. data/lib/rims/pool.rb +88 -0
  23. data/lib/rims/protocol.rb +71 -0
  24. data/lib/rims/protocol/decoder.rb +1469 -0
  25. data/lib/rims/protocol/parser.rb +1114 -0
  26. data/lib/rims/rfc822.rb +456 -0
  27. data/lib/rims/server.rb +567 -0
  28. data/lib/rims/test.rb +391 -0
  29. data/lib/rims/version.rb +11 -0
  30. data/load_test/Rakefile +93 -0
  31. data/rims.gemspec +38 -0
  32. data/test/test_auth.rb +174 -0
  33. data/test/test_cksum_kvs.rb +121 -0
  34. data/test/test_config.rb +533 -0
  35. data/test/test_daemon_status_file.rb +169 -0
  36. data/test/test_daemon_waitpid.rb +72 -0
  37. data/test/test_db.rb +602 -0
  38. data/test/test_db_recovery.rb +732 -0
  39. data/test/test_error.rb +97 -0
  40. data/test/test_gdbm_kvs.rb +32 -0
  41. data/test/test_hash_kvs.rb +116 -0
  42. data/test/test_lock.rb +161 -0
  43. data/test/test_mail_store.rb +750 -0
  44. data/test/test_passwd.rb +203 -0
  45. data/test/test_protocol.rb +91 -0
  46. data/test/test_protocol_auth.rb +121 -0
  47. data/test/test_protocol_decoder.rb +6490 -0
  48. data/test/test_protocol_fetch.rb +994 -0
  49. data/test/test_protocol_request.rb +332 -0
  50. data/test/test_protocol_search.rb +974 -0
  51. data/test/test_rfc822.rb +696 -0
  52. metadata +174 -0
@@ -0,0 +1,391 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'fileutils'
4
+ require 'set'
5
+
6
+ module RIMS
7
+ module Test
8
+ module AssertUtility
9
+ def literal(text_string)
10
+ "{#{text_string.bytesize}}\r\n#{text_string}"
11
+ end
12
+ module_function :literal
13
+
14
+ def make_header_text(name_value_pair_list, select_list: [], reject_list: [])
15
+ name_value_pair_list = name_value_pair_list.to_a.dup
16
+ select_set = select_list.map{|name| name.downcase }.to_set
17
+ reject_set = reject_list.map{|name| name.downcase }.to_set
18
+
19
+ name_value_pair_list.select!{|name, value| select_set.include? name.downcase } unless select_set.empty?
20
+ name_value_pair_list.reject!{|name, value| reject_set.include? name.downcase } unless reject_set.empty?
21
+ name_value_pair_list.map{|name, value| "#{name}: #{value}\r\n" }.join('') + "\r\n"
22
+ end
23
+ module_function :make_header_text
24
+
25
+ def message_data_list(msg_data_array)
26
+ msg_data_array.map{|msg_data|
27
+ case (msg_data)
28
+ when String
29
+ msg_data
30
+ when Array
31
+ '(' << message_data_list(msg_data) << ')'
32
+ else
33
+ raise "unknown message data: #{msg_data}"
34
+ end
35
+ }.join(' ')
36
+ end
37
+ module_function :message_data_list
38
+
39
+ def make_body(description)
40
+ reader = RIMS::Protocol::RequestReader.new(StringIO.new('', 'r'), StringIO.new('', 'w'), Logger.new(STDOUT))
41
+ reader.parse(reader.scan_line(description))[0]
42
+ end
43
+ private :make_body
44
+
45
+ def assert_strenc_equal(expected_enc, expected_str, expr_str)
46
+ assert_equal(Encoding.find(expected_enc), expr_str.encoding)
47
+ assert_equal(expected_str.dup.force_encoding(expected_enc), expr_str)
48
+ end
49
+ module_function :assert_strenc_equal
50
+ end
51
+
52
+ module PseudoAuthenticationUtility
53
+ def make_pseudo_time_source(src_time)
54
+ t = src_time
55
+ proc{
56
+ t = t + 1
57
+ t.dup
58
+ }
59
+ end
60
+ module_function :make_pseudo_time_source
61
+
62
+ def make_pseudo_random_string_source(random_seed)
63
+ r = Random.new(random_seed)
64
+ proc{ r.bytes(16).each_byte.map{|c| format('%02x', c ) }.join('') }
65
+ end
66
+ module_function :make_pseudo_random_string_source
67
+ end
68
+
69
+ module ProtocolFetchMailSample
70
+ def make_mail_simple
71
+ @simple_mail = RIMS::RFC822::Message.new(<<-'EOF')
72
+ To: foo@nonet.org
73
+ From: bar@nonet.org
74
+ Subject: test
75
+ MIME-Version: 1.0
76
+ Content-Type: text/plain; charset=us-ascii
77
+ Content-Transfer-Encoding: 7bit
78
+ Date: Fri, 8 Nov 2013 06:47:50 +0900 (JST)
79
+
80
+ Hello world.
81
+ EOF
82
+ end
83
+ private :make_mail_simple
84
+
85
+ def make_mail_multipart
86
+ @mpart_mail = RIMS::RFC822::Message.new(<<-'EOF')
87
+ To: bar@nonet.com
88
+ From: foo@nonet.com
89
+ Subject: multipart test
90
+ MIME-Version: 1.0
91
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
92
+ Content-Type: multipart/mixed; boundary="1383.905529.351297"
93
+
94
+ --1383.905529.351297
95
+ Content-Type: text/plain; charset=us-ascii
96
+
97
+ Multipart test.
98
+ --1383.905529.351297
99
+ Content-Type: application/octet-stream
100
+
101
+ 0123456789
102
+ --1383.905529.351297
103
+ Content-Type: message/rfc822
104
+
105
+ To: bar@nonet.com
106
+ From: foo@nonet.com
107
+ Subject: inner multipart
108
+ MIME-Version: 1.0
109
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
110
+ Content-Type: multipart/mixed; boundary="1383.905529.351298"
111
+
112
+ --1383.905529.351298
113
+ Content-Type: text/plain; charset=us-ascii
114
+
115
+ Hello world.
116
+ --1383.905529.351298
117
+ Content-Type: application/octet-stream
118
+
119
+ 9876543210
120
+ --1383.905529.351298--
121
+ --1383.905529.351297
122
+ Content-Type: multipart/mixed; boundary="1383.905529.351299"
123
+
124
+ --1383.905529.351299
125
+ Content-Type: image/gif
126
+
127
+ --1383.905529.351299
128
+ Content-Type: message/rfc822
129
+
130
+ To: bar@nonet.com
131
+ From: foo@nonet.com
132
+ Subject: inner multipart
133
+ MIME-Version: 1.0
134
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
135
+ Content-Type: multipart/mixed; boundary="1383.905529.351300"
136
+
137
+ --1383.905529.351300
138
+ Content-Type: text/plain; charset=us-ascii
139
+
140
+ HALO
141
+ --1383.905529.351300
142
+ Content-Type: multipart/alternative; boundary="1383.905529.351301"
143
+
144
+ --1383.905529.351301
145
+ Content-Type: text/plain; charset=us-ascii
146
+
147
+ alternative message.
148
+ --1383.905529.351301
149
+ Content-Type: text/html; charset=us-ascii
150
+
151
+ <html>
152
+ <body><p>HTML message</p></body>
153
+ </html>
154
+ --1383.905529.351301--
155
+ --1383.905529.351300--
156
+ --1383.905529.351299--
157
+ --1383.905529.351297--
158
+ EOF
159
+ end
160
+ private :make_mail_multipart
161
+
162
+ def make_mail_mime_subject
163
+ @mime_subject_mail = RIMS::RFC822::Message.new(<<-'EOF')
164
+ Date: Fri, 8 Nov 2013 19:31:03 +0900
165
+ Subject: =?ISO-2022-JP?B?GyRCJEYkOSRIGyhC?=
166
+ From: foo@nonet.com, bar <bar@nonet.com>
167
+ Sender: foo@nonet.com
168
+ Reply-To: foo@nonet.com
169
+ To: alice@test.com, bob <bob@test.com>
170
+ Cc: Kate <kate@test.com>
171
+ Bcc: foo@nonet.com
172
+ In-Reply-To: <20131106081723.5KJU1774292@smtp.testt.com>
173
+ Message-Id: <20131107214750.445A1255B9F@smtp.nonet.com>
174
+
175
+ Hello world.
176
+ EOF
177
+ end
178
+ private :make_mail_mime_subject
179
+
180
+ def make_mail_empty
181
+ @empty_mail = RIMS::RFC822::Message.new('')
182
+ end
183
+ private :make_mail_empty
184
+
185
+ def make_mail_no_body
186
+ @no_body_mail = RIMS::RFC822::Message.new('foo')
187
+ end
188
+ private :make_mail_no_body
189
+
190
+ def make_mail_address_header_pattern
191
+ @address_header_pattern_mail = RIMS::RFC822::Message.new(<<-'EOF')
192
+ To: "foo@nonet.org" <foo@nonet.org>
193
+ From: bar@nonet.org
194
+ Subject: test
195
+ MIME-Version: 1.0
196
+ Content-Type: text/plain; charset=us-ascii
197
+ Content-Transfer-Encoding: 7bit
198
+ Date: Fri, 8 Nov 2013 06:47:50 +0900 (JST)
199
+
200
+ Hello world.
201
+ EOF
202
+ end
203
+ private :make_mail_address_header_pattern
204
+ end
205
+
206
+ module KeyValueStoreTestUtility
207
+ def open_database
208
+ raise NotImplementedError, "not implemented to open `#{@name}'"
209
+ end
210
+
211
+ def make_key_value_store
212
+ raise NotImplementedError, 'not implemented.'
213
+ end
214
+
215
+ def db_close
216
+ @db.close
217
+ end
218
+
219
+ def db_closed?
220
+ @db.closed?
221
+ end
222
+
223
+ def db_fetch(key)
224
+ @db[key]
225
+ end
226
+
227
+ def db_key?(key)
228
+ @db.key? key
229
+ end
230
+
231
+ def db_each_key
232
+ return enum_for(:db_each_key) unless block_given?
233
+ @db.each_key do |key|
234
+ yield(key)
235
+ end
236
+ end
237
+
238
+ def setup
239
+ @base_dir = 'kvs_test_dir'
240
+ FileUtils.mkdir_p(@base_dir)
241
+ @name = File.join(@base_dir, "kvs_test.db.#{$$}")
242
+
243
+ @db = open_database
244
+ @kvs = make_key_value_store
245
+ end
246
+
247
+ def teardown
248
+ db_close unless db_closed?
249
+ FileUtils.rm_rf(@base_dir)
250
+ end
251
+
252
+ def test_store_fetch
253
+ assert_nil(db_fetch('foo'))
254
+ assert_nil(@kvs['foo'])
255
+
256
+ assert_equal('apple', (@kvs['foo'] = 'apple'))
257
+ assert_equal('apple', db_fetch('foo'))
258
+ assert_equal('apple', @kvs['foo'])
259
+
260
+ # update
261
+ assert_equal('banana', (@kvs['foo'] = 'banana'))
262
+ assert_equal('banana', db_fetch('foo'))
263
+ assert_equal('banana', @kvs['foo'])
264
+ end
265
+
266
+ def test_delete
267
+ assert_nil(@kvs.delete('foo'))
268
+
269
+ @kvs['foo'] = 'apple'
270
+ assert_equal('apple', @kvs.delete('foo'))
271
+
272
+ assert_nil(db_fetch('foo'))
273
+ assert_nil(@kvs['foo'])
274
+ end
275
+
276
+ def test_key?
277
+ assert_equal(false, (db_key? 'foo'))
278
+ assert_equal(false, (@kvs.key? 'foo'))
279
+
280
+ @kvs['foo'] = 'apple'
281
+ assert_equal(true, (db_key? 'foo'))
282
+ assert_equal(true, (@kvs.key? 'foo'))
283
+
284
+ # update
285
+ @kvs['foo'] = 'banana'
286
+ assert_equal(true, (db_key? 'foo'))
287
+ assert_equal(true, (@kvs.key? 'foo'))
288
+
289
+ @kvs.delete('foo')
290
+ assert_equal(false, (db_key? 'foo'))
291
+ assert_equal(false, (@kvs.key? 'foo'))
292
+ end
293
+
294
+ def test_each_key
295
+ assert_equal(%w[], db_each_key.to_a)
296
+ assert_equal(%w[], @kvs.each_key.to_a)
297
+
298
+ @kvs['foo'] = 'apple'
299
+ assert_equal(%w[ foo ], db_each_key.to_a)
300
+ assert_equal(%w[ foo ], @kvs.each_key.to_a)
301
+ assert_equal(%w[ apple ], @kvs.each_value.to_a)
302
+ assert_equal([ %w[ foo apple ] ], @kvs.each_pair.to_a)
303
+
304
+ @kvs['bar'] = 'banana'
305
+ assert_equal(%w[ foo bar ].sort, db_each_key.sort)
306
+ assert_equal(%w[ foo bar ].sort, @kvs.each_key.sort)
307
+ assert_equal(%w[ apple banana ].sort, @kvs.each_value.sort)
308
+ assert_equal([ %w[ foo apple ], %w[ bar banana ] ].sort, @kvs.each_pair.sort)
309
+
310
+ @kvs['baz'] = 'orange'
311
+ assert_equal(%w[ foo bar baz ].sort, db_each_key.sort)
312
+ assert_equal(%w[ foo bar baz ].sort, @kvs.each_key.sort)
313
+ assert_equal(%w[ apple banana orange ].sort, @kvs.each_value.sort)
314
+ assert_equal([ %w[ foo apple ], %w[ bar banana ], %w[ baz orange ] ].sort, @kvs.each_pair.sort)
315
+
316
+ @kvs.delete('bar')
317
+ assert_equal(%w[ foo baz ].sort, db_each_key.sort)
318
+ assert_equal(%w[ foo baz ].sort, @kvs.each_key.sort)
319
+ assert_equal(%w[ apple orange ].sort, @kvs.each_value.sort)
320
+ assert_equal([ %w[ foo apple ], %w[ baz orange ] ].sort, @kvs.each_pair.sort)
321
+
322
+ # update
323
+ @kvs['baz'] = 'melon'
324
+ assert_equal(%w[ foo baz ].sort, db_each_key.sort)
325
+ assert_equal(%w[ foo baz ].sort, @kvs.each_key.sort)
326
+ assert_equal(%w[ apple melon ].sort, @kvs.each_value.sort)
327
+ assert_equal([ %w[ foo apple ], %w[ baz melon ] ].sort, @kvs.each_pair.sort)
328
+ end
329
+
330
+ def test_sync
331
+ @kvs.sync
332
+ end
333
+
334
+ def test_close
335
+ @kvs.close
336
+ assert_equal(true, db_closed?)
337
+
338
+ # closed exception
339
+ assert_raise(RuntimeError) { @kvs['foo'] }
340
+ assert_raise(RuntimeError) { @kvs['foo'] = 'apple' }
341
+ assert_raise(RuntimeError) { @kvs.delete('foo') }
342
+ assert_raise(RuntimeError) { @kvs.key? 'foo' }
343
+ assert_raise(RuntimeError) { @kvs.each_key.to_a }
344
+ assert_raise(RuntimeError) { @kvs.each_value.to_a }
345
+ assert_raise(RuntimeError) { @kvs.each_pair.to_a }
346
+ end
347
+ end
348
+
349
+ module KeyValueStoreOpenCloseTestUtility
350
+ def get_kvs_name
351
+ raise NotImplementedError, 'not implemented.'
352
+ end
353
+
354
+ def get_config
355
+ {}
356
+ end
357
+
358
+ def setup
359
+ @base_dir = 'kvs_open_close_test_dir'
360
+ @name = File.join(@base_dir, 'test_kvs')
361
+ FileUtils.mkdir_p(@base_dir)
362
+
363
+ @Test_KeyValueStore = RIMS::KeyValueStore::FactoryBuilder.get_plug_in(get_kvs_name)
364
+ end
365
+
366
+ def teardown
367
+ FileUtils.rm_rf(@base_dir)
368
+ end
369
+
370
+ def test_open_close
371
+ assert_equal(false, (@Test_KeyValueStore.exist? @name))
372
+
373
+ kvs = @Test_KeyValueStore.open_with_conf(@name, get_config)
374
+ begin
375
+ assert_equal(true, (@Test_KeyValueStore.exist? @name))
376
+ ensure
377
+ kvs.close
378
+ end
379
+ assert_equal(true, (@Test_KeyValueStore.exist? @name))
380
+
381
+ kvs.destroy
382
+ assert_equal(false, (@Test_KeyValueStore.exist? @name))
383
+ end
384
+ end
385
+ end
386
+ end
387
+
388
+ # Local Variables:
389
+ # mode: Ruby
390
+ # indent-tabs-mode: nil
391
+ # End:
@@ -0,0 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RIMS
4
+ VERSION = '0.2.1'
5
+ MAILBOX_DATA_STRUCTURE_VERSION = 'mailbox.2'
6
+ end
7
+
8
+ # Local Variables:
9
+ # mode: Ruby
10
+ # indent-tabs-mode: nil
11
+ # End:
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'rake/clean'
4
+ require 'yaml'
5
+
6
+ def start_pgrp(*cmds)
7
+ pgid = fork{
8
+ Process.setpgid($$, $$)
9
+ sh *cmds
10
+ }
11
+ Process.setpgid(pgid, pgid)
12
+
13
+ pgid
14
+ end
15
+
16
+ def run_server(*options)
17
+ pgid = start_pgrp('rims', 'server', *options)
18
+ begin
19
+ sleep 1
20
+ yield
21
+ ensure
22
+ Process.kill('TERM', -pgid)
23
+ Process.wait
24
+ end
25
+ end
26
+
27
+ def run_server_conf(path, conf, *options)
28
+ mkdir_p(path)
29
+
30
+ path_conf = File.join(path, 'config.yml')
31
+ IO.write(path_conf, conf.to_yaml)
32
+
33
+ run_server('-f', path_conf, *options) do
34
+ yield
35
+ end
36
+ end
37
+
38
+ def get_mail_file_list
39
+ FileUtils.mkdir 'mails' unless (File.directory? 'mails')
40
+ mail_file_list = Dir.entries('mails').map{|name| File.join('mails', name) }.select{|path| File.file? path }
41
+ if (mail_file_list.empty?) then
42
+ warn('WARNING: not found mail file(s) at a directory: mails/')
43
+ end
44
+ mail_file_list
45
+ end
46
+
47
+ def time_shell(*cmds)
48
+ sh 'time', '-p', '--', *cmds
49
+ end
50
+
51
+ PASSWD = {
52
+ 'foo' => 'foo',
53
+ '#postman' => '#postman'
54
+ }
55
+
56
+ USER_CONF = { 'user_list' => [] }
57
+ for user, pass in PASSWD
58
+ USER_CONF['user_list'].push({ 'user' => user, 'pass' => pass })
59
+ end
60
+
61
+ desc 'load test: rims post-mail'
62
+ task :post_mail do
63
+ mail_file_list = get_mail_file_list
64
+ puts "#{mail_file_list.length} mails."
65
+ run_server_conf('post_mail', USER_CONF, *%w[ -v quiet -l info --imap-host=localhost --imap-port=14300 ]) do
66
+ time_shell 'rims', 'post-mail', '--no-verbose', '--host=localhost', '--port=14300', '--username=#postman', "--password=#{PASSWD['#postman']}", 'foo', *mail_file_list
67
+ end
68
+ end
69
+
70
+ CLOBBER.include('post_mail')
71
+
72
+ desc 'load test: rims imap-append'
73
+ task :imap_append do
74
+ mail_file_list = get_mail_file_list
75
+ puts "#{mail_file_list.length} mails."
76
+ run_server_conf('imap_append', USER_CONF, *%w[ -v quiet -l info --imap-host=localhost --imap-port=14300 ]) do
77
+ time_shell 'rims', 'imap-append', '--no-verbose', '--host=localhost', '--port=14300', '--username=foo', "--password=#{PASSWD['foo']}", *mail_file_list
78
+ end
79
+ end
80
+
81
+ desc 'run server'
82
+ task :run_server do
83
+ run_server_conf('imap_server', USER_CONF, *%w[ -v debug -l debug --imap-host=localhost --imap-port=14300 ]) do
84
+ sleep
85
+ end
86
+ end
87
+
88
+ CLOBBER.include('imap_append')
89
+
90
+ # Local Variables:
91
+ # mode: Ruby
92
+ # indent-tabs-mode: nil
93
+ # End: