String#hash is not stable across processes :<
[metropolis.git] / test / test_tc_hdb.rb
blob690fb8282edf9183d1596df4b2629d6f2bbc4d22
1 # -*- encoding: binary -*-
2 require './test/rack_read_write.rb'
3 require 'tokyocabinet' # FIXME: emits warning with 1.29 gem
4 $-w = true
5 require 'metropolis'
7 class Test_TC_HDB < Test::Unit::TestCase
8   attr_reader :tmp, :o, :uri
9   include TestRackReadWrite
11   def setup
12     tmp = Tempfile.new('tchdb')
13     @path_pattern = tmp.path + ".%01x.tch"
14     tmp.close!
15     @uri = "tc:///"
16     @app_opts = { :path_pattern => @path_pattern, :uri => @uri }
17   end
19   def teardown
20     Dir[@path_pattern.sub!(/%\d*x/, '*')].each { |x| File.unlink(x) }
21   end
23   def osetup
24     Metropolis.new(@app_opts)
25   end
27   def test_create_put_get_delete
28     o = osetup
29     r = o.put('hello', { 'rack.input' => StringIO.new('world') })
30     assert_equal 201, r[0].to_i
31     assert_equal 'text/plain', r[1]['Content-Type']
32     assert_equal '8', r[1]['Content-Length']
33     assert_equal "Created\n", r[2].join('')
35     r = o.put('hellox', { 'rack.input' => StringIO.new('worldx') })
36     assert_equal 201, r[0].to_i
37     assert_equal 'text/plain', r[1]['Content-Type']
38     assert_equal '8', r[1]['Content-Length']
39     assert_equal "Created\n", r[2].join('')
41     r = o.get('hello', {})
42     assert_equal 200, r[0].to_i
43     assert_equal 'application/octet-stream', r[1]['Content-Type']
44     assert_equal '5', r[1]['Content-Length']
45     assert_equal %w(world), r[2]
47     r = o.head('hello', {})
48     assert_equal 200, r[0].to_i
49     assert_equal 'application/octet-stream', r[1]['Content-Type']
50     assert_equal '5', r[1]['Content-Length']
51     assert_equal [], r[2]
53     r = o.get('hellox', {})
54     assert_equal 200, r[0].to_i
55     assert_equal 'application/octet-stream', r[1]['Content-Type']
56     assert_equal '6', r[1]['Content-Length']
57     assert_equal %w(worldx), r[2]
59     r = o.delete('hellox')
60     assert_equal 200, r[0].to_i
61     assert_equal 'text/plain', r[1]['Content-Type']
62     assert_equal '3', r[1]['Content-Length']
63     assert_equal "OK\n", r[2].join('')
65     r = o.delete('hellox')
66     assert_equal 404, r[0].to_i
67     assert_equal 'text/plain', r[1]['Content-Type']
68     assert_equal '10', r[1]['Content-Length']
69     assert_equal "Not Found\n", r[2].join('')
71     r = o.get('hellox', {})
72     assert_equal 404, r[0].to_i
73     assert_equal 'text/plain', r[1]['Content-Type']
74     assert_equal '10', r[1]['Content-Length']
75     assert_equal "Not Found\n", r[2].join('')
77     r = o.head('hellox', {})
78     assert_equal 404, r[0].to_i
79     assert_equal 'text/plain', r[1]['Content-Type']
80     assert_equal '10', r[1]['Content-Length']
81     assert_equal "", r[2].join('')
82   end
84   def test_putkeep
85     o = osetup
86     env = {
87       "rack.input" => StringIO.new("hello"),
88       "HTTP_X_TT_PDMODE" => "1"
89     }
90     assert_equal 201, o.put("x", env)[0]
91     env["rack.input"] = StringIO.new("wrong")
92     assert_equal 409, o.put("x", env)[0]
93     assert_equal "hello", o.get("x", {})[2].join('')
94   end
96   def test_putcat
97     o = osetup
98     env = {
99       "rack.input" => StringIO.new("hello"),
100       "HTTP_X_TT_PDMODE" => "2"
101     }
102     assert_equal 201, o.put("x", env)[0]
103     env["rack.input"] = StringIO.new("MOAR")
104     assert_equal 201, o.put("x", env)[0]
105     assert_equal "helloMOAR", o.get("x", {})[2].join('')
106   end
108   def test_multiproc
109     nr = 2
110     key = "k"
111     str = "." * (1024 * 1024)
112     nr.times {
113       fork {
114         o = osetup
115         sio = StringIO.new(str)
116         env = { "rack.input" => sio }
117         100.times {
118           o.put(key, env)
119           sio.rewind
120           o.get(key, {})
121         }
122       }
123     }
124     res = Process.waitall
125     assert_equal nr, res.size
126     res.each { |(pid, status)| assert status.success? }
127   end if ENV["TEST_EXPENSIVE"]
129   def test_readonly
130     key = "x"
131     wr = osetup
132     wr.put(key, { "rack.input" => StringIO.new("OK") })
133     o = Metropolis.new(@app_opts.merge(:readonly => true))
134     %w(PUT DELETE).each do |rm|
135       env = {
136         "rack.input" => StringIO.new("FAIL"),
137         "REQUEST_METHOD" => rm,
138         "PATH_INFO" => "/#{key}"
139       }
140       assert_equal 403, o.call(env)[0]
141     end
142     env = {
143       "REQUEST_METHOD" => "GET",
144       "PATH_INFO" => "/#{key}",
145     }
146     assert_equal 200, o.call(env)[0]
147     assert_equal '2', o.call(env)[1]["Content-Length"]
148     assert_equal 'application/octet-stream', o.call(env)[1]["Content-Type"]
149     assert_equal "OK", o.call(env)[2].join('')
151     env["REQUEST_METHOD"] = "HEAD"
152     assert_equal 200, o.call(env)[0]
153     assert_equal '2', o.call(env)[1]["Content-Length"]
154     assert_equal 'application/octet-stream', o.call(env)[1]["Content-Type"]
155     assert_equal "", o.call(env)[2].join('')
156   end
158   def test_create_toplevel
159     k = "x"
160     nr_bytes = 1024 * 1024 * 20
161     data = "0" * nr_bytes
162     obj = nil
163     assert_nothing_raised { obj = Metropolis.new(@app_opts) }
165     query = "large=true&apow=3&bnum=65536&compress=deflate"
166     assert_nothing_raised {
167       obj = Metropolis.new(@app_opts.merge(:uri => "#{uri}?#{query}"))
168     }
169     optimize_args = obj.instance_variable_get(:@optimize)
170     flags = TokyoCabinet::HDB::TLARGE | TokyoCabinet::HDB::TDEFLATE
171     assert_equal flags, optimize_args[3]
172     assert_equal 65536, optimize_args[0]
173     assert_nil optimize_args[2]
174     assert_equal 3, optimize_args[1]
175     assert_nothing_raised { obj.get(k, {}) }
176     assert_nothing_raised { obj.put(k,{'rack.input' => StringIO.new(data)}) }
178     opts = @app_opts.merge(:uri => "#{uri}?#{query}", :readonly => true)
179     obj = Metropolis.new(opts)
180     assert_equal data, obj.get(k, {})[2].join('')
181     obj.close!
183     opts = @app_opts.merge(:uri => uri, :readonly => true)
184     obj = Metropolis.new(opts)
185     assert_equal data, obj.get(k, {})[2].join('')
186     obj.close!
187     sum = obj.instance_eval {
188       @dbv.inject(0) { |size, (hdb,path)| size += File.stat(path).size }
189     }
190     assert sum <= nr_bytes, "#{sum} > #{nr_bytes}"
191     obj.close!
192   end
194   def test_exclusive
195     opts = @app_opts.merge(:uri => uri, :exclusive => true)
196     @app = Metropolis.new(opts)
197     assert_equal(app.method(:reader), app.method(:writer))
198     basic_rest
199   end
201   def test_no_rdlock
202     opts = @app_opts.merge(:uri => "#{uri}?rdlock=false")
203     @app = Metropolis.new(opts)
204     nolck = ::TokyoCabinet::HDB::ONOLCK
205     flags = @app.instance_variable_get(:@rd_flags)
206     assert((flags & nolck) == nolck)
207     flags = @app.instance_variable_get(:@wr_flags)
208     assert((flags & nolck) == 0)
209     basic_rest
210   end
212   def test_no_wrlock
213     @app = Metropolis.new(@app_opts.merge(:uri => "#{uri}?wrlock=false"))
214     nolck = ::TokyoCabinet::HDB::ONOLCK
215     flags = @app.instance_variable_get(:@wr_flags)
216     assert((flags & nolck) == nolck)
217     flags = @app.instance_variable_get(:@rd_flags)
218     assert((flags & nolck) == 0)
219     basic_rest
220   end