scalaroid 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,370 @@
1
+ module Scalaroid
2
+ # Abstracts connections to Scalaris using JSON
3
+ class JSONConnection
4
+ # Creates a JSON connection to the given URL using the given TCP timeout (or default)
5
+ def initialize(url = DEFAULT_URL, timeout = nil)
6
+ begin
7
+ @uri = URI.parse(url)
8
+ @timeout = timeout
9
+ start
10
+ rescue Exception => error
11
+ raise ConnectionError.new(error)
12
+ end
13
+ end
14
+
15
+ def start
16
+ if @conn == nil or not @conn.started?
17
+ @conn = Net::HTTP.start(@uri.host, @uri.port)
18
+ unless @timeout.nil?
19
+ @conn.read_timeout = @timeout
20
+ end
21
+ end
22
+ end
23
+ private :start
24
+
25
+ # Calls the given function with the given parameters via the JSON
26
+ # interface of Scalaris.
27
+ def call(function, params)
28
+ start
29
+ req = Net::HTTP::Post.new(DEFAULT_PATH)
30
+ req.add_field('Content-Type', 'application/json; charset=utf-8')
31
+ req.body = URI::encode({
32
+ :jsonrpc => :'2.0',
33
+ :method => function,
34
+ :params => params,
35
+ :id => 0 }.to_json({:ascii_only => true}))
36
+ begin
37
+ res = @conn.request(req)
38
+ if res.is_a?(Net::HTTPSuccess)
39
+ data = res.body
40
+ return JSON.parse(data)['result']
41
+ else
42
+ raise ConnectionError.new(res)
43
+ end
44
+ rescue ConnectionError => error
45
+ raise error
46
+ rescue Exception => error
47
+ raise ConnectionError.new(error)
48
+ end
49
+ end
50
+
51
+ # Encodes the value to the form required by the Scalaris JSON API
52
+ def self.encode_value(value, binary = false)
53
+ if binary
54
+ return { :type => :as_bin, :value => Base64.encode64(value) }
55
+ else
56
+ return { :type => :as_is, :value => value }
57
+ end
58
+ end
59
+
60
+ # Decodes the value from the Scalaris JSON API form to a native type
61
+ def self.decode_value(value)
62
+ if not (value.has_key?('type') and value.has_key?('value'))
63
+ raise ConnectionError.new(value)
64
+ end
65
+ if value['type'] == 'as_bin'
66
+ return Base64.decode64(value['value'])
67
+ else
68
+ return value['value']
69
+ end
70
+ end
71
+
72
+ # Processes the result of some Scalaris operation and raises a
73
+ # TimeoutError if found.
74
+ #
75
+ # result: {'status': 'ok'} or
76
+ # {'status': 'fail', 'reason': 'timeout'}
77
+ def self.check_fail_abort(result)
78
+ if result == {:status => 'fail', :reason => 'timeout'}
79
+ raise TimeoutError.new(result)
80
+ end
81
+ end
82
+
83
+ # Processes the result of a read operation.
84
+ # Returns the read value on success.
85
+ # Raises the appropriate exception if the operation failed.
86
+ #
87
+ # result: {'status' => 'ok', 'value': xxx} or
88
+ # {'status' => 'fail', 'reason' => 'timeout' or 'not_found'}
89
+ def self.process_result_read(result)
90
+ if result.is_a?(Hash) and result.has_key?('status') and result.length == 2
91
+ if result['status'] == 'ok' and result.has_key?('value')
92
+ return decode_value(result['value'])
93
+ elsif result['status'] == 'fail' and result.has_key?('reason')
94
+ if result['reason'] == 'timeout'
95
+ raise TimeoutError.new(result)
96
+ elsif result['reason'] == 'not_found'
97
+ raise NotFoundError.new(result)
98
+ end
99
+ end
100
+ end
101
+ raise UnknownError.new(result)
102
+ end
103
+
104
+ # Processes the result of a write operation.
105
+ # Raises the appropriate exception if the operation failed.
106
+ #
107
+ # result: {'status' => 'ok'} or
108
+ # {'status' => 'fail', 'reason' => 'timeout'}
109
+ def self.process_result_write(result)
110
+ if result.is_a?(Hash)
111
+ if result == {'status' => 'ok'}
112
+ return true
113
+ elsif result == {'status' => 'fail', 'reason' => 'timeout'}
114
+ raise TimeoutError.new(result)
115
+ end
116
+ end
117
+ raise UnknownError.new(result)
118
+ end
119
+
120
+ # Processes the result of a commit operation.
121
+ # Raises the appropriate exception if the operation failed.
122
+ #
123
+ # result: {'status' => 'ok'} or
124
+ # {'status' => 'fail', 'reason' => 'abort', 'keys' => <list>} or
125
+ # {'status' => 'fail', 'reason' => 'timeout'}
126
+ def self.process_result_commit(result)
127
+ if result.is_a?(Hash) and result.has_key?('status')
128
+ if result == {'status' => 'ok'}
129
+ return true
130
+ elsif result['status'] == 'fail' and result.has_key?('reason')
131
+ if result.length == 2 and result['reason'] == 'timeout'
132
+ raise TimeoutError.new(result)
133
+ elsif result.length == 3 and result['reason'] == 'abort' and result.has_key?('keys')
134
+ raise AbortError.new(result, result['keys'])
135
+ end
136
+ end
137
+ end
138
+ raise UnknownError.new(result)
139
+ end
140
+
141
+ # Processes the result of a add_del_on_list operation.
142
+ # Raises the appropriate exception if the operation failed.
143
+ #
144
+ # results: {'status': 'ok'} or
145
+ # {'status': 'fail', 'reason': 'timeout' or 'not_a_list'}
146
+ def self.process_result_add_del_on_list(result)
147
+ if result.is_a?(Hash) and result.has_key?('status')
148
+ if result == {'status' => 'ok'}
149
+ return nil
150
+ elsif result['status'] == 'fail' and result.has_key?('reason')
151
+ if result.length == 2
152
+ if result['reason'] == 'timeout'
153
+ raise TimeoutError.new(result)
154
+ elsif result['reason'] == 'not_a_list'
155
+ raise NotAListError.new(result)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ raise UnknownError.new(result)
161
+ end
162
+
163
+ # Processes the result of a add_on_nr operation.
164
+ # Raises the appropriate exception if the operation failed.
165
+ #
166
+ # results: {'status': 'ok'} or
167
+ # {'status': 'fail', 'reason': 'timeout' or 'not_a_number'}
168
+ def self.process_result_add_on_nr(result)
169
+ if result.is_a?(Hash) and result.has_key?('status')
170
+ if result == {'status' => 'ok'}
171
+ return nil
172
+ elsif result['status'] == 'fail' and result.has_key?('reason')
173
+ if result.length == 2
174
+ if result['reason'] == 'timeout'
175
+ raise TimeoutError.new(result)
176
+ elsif result['reason'] == 'not_a_number'
177
+ raise NotANumberError.new(result)
178
+ end
179
+ end
180
+ end
181
+ end
182
+ raise UnknownError.new(result)
183
+ end
184
+
185
+ # Processes the result of a test_and_set operation.
186
+ # Raises the appropriate exception if the operation failed.
187
+ #
188
+ # results: {'status' => 'ok'} or
189
+ # {'status' => 'fail', 'reason' => 'timeout' or 'not_found'} or
190
+ # {'status' => 'fail', 'reason' => 'key_changed', 'value': xxx}
191
+ def self.process_result_test_and_set(result)
192
+ if result.is_a?(Hash) and result.has_key?('status')
193
+ if result == {'status' => 'ok'}
194
+ return nil
195
+ elsif result['status'] == 'fail' and result.has_key?('reason')
196
+ if result.length == 2
197
+ if result['reason'] == 'timeout'
198
+ raise TimeoutError.new(result)
199
+ elsif result['reason'] == 'not_found'
200
+ raise NotFoundError.new(result)
201
+ end
202
+ elsif result['reason'] == 'key_changed' and result.has_key?('value') and result.length == 3
203
+ raise KeyChangedError.new(result, decode_value(result['value']))
204
+ end
205
+ end
206
+ end
207
+ raise UnknownError.new(result)
208
+ end
209
+
210
+ # Processes the result of a publish operation.
211
+ # Raises the appropriate exception if the operation failed.
212
+ #
213
+ # results: {'status': 'ok'}
214
+ def self.process_result_publish(result)
215
+ if result == {'status' => 'ok'}
216
+ return nil
217
+ end
218
+ raise UnknownError.new(result)
219
+ end
220
+
221
+ # Processes the result of a subscribe operation.
222
+ # Raises the appropriate exception if the operation failed.
223
+ #
224
+ # results: {'status': 'ok'} or
225
+ # {'status': 'fail', 'reason': 'timeout' or 'abort'}
226
+ def self.process_result_subscribe(result)
227
+ process_result_commit(result)
228
+ end
229
+
230
+ # Processes the result of a unsubscribe operation.
231
+ # Raises the appropriate exception if the operation failed.
232
+ #
233
+ # results: {'status': 'ok'} or
234
+ # {'status': 'fail', 'reason': 'timeout' or 'abort' or 'not_found'}
235
+ def self.process_result_unsubscribe(result)
236
+ if result == {'status' => 'ok'}
237
+ return nil
238
+ elsif result.is_a?(Hash) and result.has_key?('status')
239
+ if result['status'] == 'fail' and result.has_key?('reason')
240
+ if result.length == 2
241
+ if result['reason'] == 'timeout'
242
+ raise TimeoutError.new(result)
243
+ elsif result['reason'] == 'not_found'
244
+ raise NotFoundError.new(result)
245
+ end
246
+ elsif result.length == 3 and result['reason'] == 'abort' and result.has_key?('keys')
247
+ raise AbortError.new(result, result['keys'])
248
+ end
249
+ end
250
+ end
251
+ raise UnknownError.new(result)
252
+ end
253
+
254
+ # Processes the result of a get_subscribers operation.
255
+ # Returns the list of subscribers on success.
256
+ # Raises the appropriate exception if the operation failed.
257
+ #
258
+ # results: [urls=str()]
259
+ def self.process_result_get_subscribers(result)
260
+ if result.is_a?(Array)
261
+ return result
262
+ end
263
+ raise UnknownError.new(result)
264
+ end
265
+
266
+ # Processes the result of a delete operation.
267
+ # Returns an Array of
268
+ # {:success => true | :timeout, :ok => <number of deleted items>, :results => <detailed results>}
269
+ # on success.
270
+ # Does not raise an exception if the operation failed unless the result
271
+ # is invalid!
272
+ #
273
+ # results: {'ok': xxx, 'results': ['ok' or 'locks_set' or 'undef']} or
274
+ # {'failure': 'timeout', 'ok': xxx, 'results': ['ok' or 'locks_set' or 'undef']}
275
+ def self.process_result_delete(result)
276
+ if result.is_a?(Hash) and result.has_key?('ok') and result.has_key?('results')
277
+ if not result.has_key?('failure')
278
+ return {:success => true,
279
+ :ok => result['ok'],
280
+ :results => result['results']}
281
+ elsif result['failure'] == 'timeout'
282
+ return {:success => :timeout,
283
+ :ok => result['ok'],
284
+ :results => result['results']}
285
+ end
286
+ end
287
+ raise UnknownError.new(result)
288
+ end
289
+
290
+ # Creates a new DeleteResult from the given result list.
291
+ #
292
+ # result: ['ok' or 'locks_set' or 'undef']
293
+ def self.create_delete_result(result)
294
+ ok = 0
295
+ locks_set = 0
296
+ undefined = 0
297
+ if result.is_a?(Array)
298
+ for element in result
299
+ if element == 'ok'
300
+ ok += 1
301
+ elsif element == 'locks_set'
302
+ locks_set += 1
303
+ elsif element == 'undef'
304
+ undefined += 1
305
+ else
306
+ raise UnknownError.new(:'Unknown reason ' + element + :'in ' + result)
307
+ end
308
+ end
309
+ return DeleteResult.new(ok, locks_set, undefined)
310
+ end
311
+ raise UnknownError.new(:'Unknown result ' + result)
312
+ end
313
+
314
+ # Processes the result of a req_list operation of the Transaction class.
315
+ # Returns the Array (:tlog => <tlog>, :result => <result>) on success.
316
+ # Raises the appropriate exception if the operation failed.
317
+ #
318
+ # results: {'tlog': xxx,
319
+ # 'results': [{'status': 'ok'} or {'status': 'ok', 'value': xxx} or
320
+ # {'status': 'fail', 'reason': 'timeout' or 'abort' or 'not_found'}]}
321
+ def self.process_result_req_list_t(result)
322
+ if (not result.has_key?('tlog')) or (not result.has_key?('results')) or
323
+ (not result['results'].is_a?(Array))
324
+ raise UnknownError.new(result)
325
+ end
326
+ {:tlog => result['tlog'], :result => result['results']}
327
+ end
328
+
329
+ # Processes the result of a req_list operation of the TransactionSingleOp class.
330
+ # Returns <result> on success.
331
+ # Raises the appropriate exception if the operation failed.
332
+ #
333
+ # results: [{'status': 'ok'} or {'status': 'ok', 'value': xxx} or
334
+ # {'status': 'fail', 'reason': 'timeout' or 'abort' or 'not_found'}]
335
+ def self.process_result_req_list_tso(result)
336
+ if not result.is_a?(Array)
337
+ raise UnknownError.new(result)
338
+ end
339
+ result
340
+ end
341
+
342
+ # Processes the result of a nop operation.
343
+ # Raises the appropriate exception if the operation failed.
344
+ #
345
+ # result: 'ok'
346
+ def self.process_result_nop(result)
347
+ if result != 'ok'
348
+ raise UnknownError.new(result)
349
+ end
350
+ end
351
+
352
+ # Returns a new ReqList object allowing multiple parallel requests for
353
+ # the Transaction class.
354
+ def self.new_req_list_t(other = nil)
355
+ JSONReqListTransaction.new(other)
356
+ end
357
+
358
+ # Returns a new ReqList object allowing multiple parallel requests for
359
+ # the TransactionSingleOp class.
360
+ def self.new_req_list_tso(other = nil)
361
+ JSONReqListTransactionSingleOp.new(other)
362
+ end
363
+
364
+ def close
365
+ if @conn.started?
366
+ @conn.finish()
367
+ end
368
+ end
369
+ end
370
+ end
@@ -0,0 +1,3 @@
1
+ module Scalaroid
2
+ VERSION = "0.0.1"
3
+ end
data/lib/scalaroid.rb ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/ruby -KU
2
+ # Copyright 2008-2011 Zuse Institute Berlin
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
+ require 'rubygems'
17
+ gem 'json', '>=1.4.1'
18
+ require 'json'
19
+ require 'net/http'
20
+ require 'base64'
21
+ require 'open-uri'
22
+
23
+ module InternalScalarisSimpleError
24
+ attr_reader :raw_result
25
+ def initialize(raw_result)
26
+ @raw_result = raw_result
27
+ end
28
+
29
+ def to_s
30
+ @raw_result
31
+ end
32
+ end
33
+
34
+ module InternalScalarisNopClose
35
+ # No operation (may be used for measuring the JSON overhead).
36
+ def nop(value)
37
+ value = @conn.class.encode_value(value)
38
+ result = @conn.call(:nop, [value])
39
+ @conn.class.process_result_nop(result)
40
+ end
41
+
42
+ # Close the connection to Scalaris
43
+ # (it will automatically be re-opened on the next request).
44
+ def close_connection
45
+ @conn.close()
46
+ end
47
+ end
48
+
49
+ # work around floating point numbers not being printed precisely enough
50
+ class Float
51
+ # note: can not override to_json (this is not done recursively, e.g. in a Hash, before ruby 1.9)
52
+ alias_method :orig_t_s, :to_s
53
+ def to_s
54
+ if not finite?
55
+ orig_to_json(*a)
56
+ else
57
+ sprintf("%#.17g", self)
58
+ end
59
+ end
60
+ end
61
+
62
+ module Scalaroid
63
+ autoload :ScalarisError, "scalaroid/errors"
64
+ autoload :AbortError, "scalaroid/errors"
65
+ autoload :ConnectionError, "scalaroid/errors"
66
+ autoload :KeyChangedError, "scalaroid/errors"
67
+ autoload :NodeNotFoundError, "scalaroid/errors"
68
+ autoload :NotFoundError, "scalaroid/errors"
69
+ autoload :NotAListError, "scalaroid/errors"
70
+ autoload :NotANumberError, "scalaroid/errors"
71
+ autoload :TimeoutError, "scalaroid/errors"
72
+ autoload :UnknownError, "scalaroid/errors"
73
+
74
+ autoload :DeleteResult, "scalaroid/delete_result"
75
+ autoload :JSONConnection, "scalaroid/json_connection"
76
+ autoload :JSONReqList, "scalaroid/json_req_list"
77
+ autoload :JSONReqListTransaction, "scalaroid/json_req_list_transaction"
78
+ autoload :JSONReqListTransactionSingleOp, "scalaroid/json_req_list_transaction_single_op"
79
+ autoload :PubSub, "scalaroid/pub_sub"
80
+ autoload :ReplicatedDHT, "scalaroid/replicated_dht"
81
+ autoload :Transaction, "scalaroid/transaction"
82
+ autoload :TransactionSingleOp, "scalaroid/transaction_single_op"
83
+ autoload :VERSION, "scalaroid/version"
84
+
85
+ # default URL and port to a scalaris node
86
+ if ENV.has_key?('SCALARIS_JSON_URL') and not ENV['SCALARIS_JSON_URL'].empty?
87
+ DEFAULT_URL = ENV['SCALARIS_JSON_URL']
88
+ else
89
+ DEFAULT_URL = 'http://localhost:8000'
90
+ end
91
+
92
+ # path to the json rpc page
93
+ DEFAULT_PATH = '/jsonrpc.yaws'
94
+
95
+
96
+ # Converts a string to a list of integers.
97
+ # If the expected value of a read operation is a list, the returned value
98
+ # could be (mistakenly) a string if it is a list of integers.
99
+ def str_to_list(value)
100
+ if value.is_a?(String)
101
+ return value.unpack("U*")
102
+ else
103
+ return value
104
+ end
105
+ end
106
+
107
+ module_function :str_to_list
108
+ end
data/scalaroid.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: scalaroid 0.0.1 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "scalaroid"
9
+ s.version = "0.0.1"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Teodor Pripoae"]
14
+ s.date = "2014-07-07"
15
+ s.description = "Ruby bindings for Scalaris forked from official Scalaris bindings"
16
+ s.email = "teodor.pripoae@gmail.com"
17
+ s.executables = ["scalaroid"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "Rakefile",
27
+ "bin/scalaroid",
28
+ "lib/scalaroid.rb",
29
+ "lib/scalaroid/json_connection.rb",
30
+ "lib/scalaroid/version.rb",
31
+ "scalaroid.gemspec",
32
+ "test/replicated_dht_test.rb",
33
+ "test/test_helper.rb",
34
+ "test/test_pub_sub.rb",
35
+ "test/transaction_single_op_test.rb",
36
+ "test/transaction_test.rb"
37
+ ]
38
+ s.homepage = "http://github.com/teodor-pripoae/scalaroid"
39
+ s.licenses = ["Apache-2.0"]
40
+ s.rubygems_version = "2.2.2"
41
+ s.summary = "Ruby bindings for Scalaris"
42
+
43
+ s.add_runtime_dependency(%q<json>, ["~> 1.7"])
44
+ s.add_development_dependency(%q<rake>, ["~> 10.0"])
45
+ s.add_development_dependency(%q<minitest>, ["~> 5.3"])
46
+ s.add_development_dependency(%q<pry>, ["= 0.9.12.6"])
47
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
48
+ end
@@ -0,0 +1,143 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestReplicatedDHT < Minitest::Test
4
+ def setup
5
+ @testTime = (Time.now.to_f * 1000).to_i
6
+ end
7
+
8
+ # Test method for ReplicatedDHT()
9
+ def test_replicated_dht1()
10
+ rdht = Scalaroid::ReplicatedDHT.new()
11
+ rdht.close_connection()
12
+ end
13
+
14
+ # Test method for ReplicatedDHT(conn)
15
+ def test_replicated_dht2()
16
+ rdht = Scalaroid::ReplicatedDHT.new(conn = Scalaroid::JSONConnection.new(url = Scalaroid::DEFAULT_URL))
17
+ rdht.close_connection()
18
+ end
19
+
20
+ # Test method for ReplicatedDHT.close_connection() trying to close the connection twice.
21
+ def test_double_close()
22
+ rdht = Scalaroid::ReplicatedDHT.new()
23
+ rdht.close_connection()
24
+ rdht.close_connection()
25
+ end
26
+
27
+ # Tries to read the value at the given key and fails if this does
28
+ # not fail with a NotFoundError.
29
+ def _checkKeyDoesNotExist(key)
30
+ conn = Scalaroid::TransactionSingleOp.new()
31
+ begin
32
+ conn.read(key)
33
+ assert(false, 'the value at ' + key + ' should not exist anymore')
34
+ rescue Scalaroid::NotFoundError
35
+ # nothing to do here
36
+ end
37
+ conn.close_connection()
38
+ end
39
+
40
+ # Test method for ReplicatedDHT.delete(key).
41
+ # Tries to delete some not existing keys.
42
+ def test_delete_not_existing_key()
43
+ key = "_Delete_NotExistingKey"
44
+ rdht = Scalaroid::ReplicatedDHT.new()
45
+
46
+ (0..($_TEST_DATA.length - 1)).each do |i|
47
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
48
+ assert_equal(0, ok)
49
+ results = rdht.get_last_delete_result()
50
+ assert_equal(0, results.ok)
51
+ assert_equal(0, results.locks_set)
52
+ assert_equal(4, results.undefined)
53
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
54
+ end
55
+
56
+ rdht.close_connection()
57
+ end
58
+
59
+ # Test method for ReplicatedDHT.delete(key) and TransactionSingleOp#write(key, value=str()).
60
+ # Inserts some values, tries to delete them afterwards and tries the delete again.
61
+ def test_delete1()
62
+ key = "_Delete1"
63
+ c = Scalaroid::JSONConnection.new(url = Scalaroid::DEFAULT_URL)
64
+ rdht = Scalaroid::ReplicatedDHT.new(conn = c)
65
+ sc = Scalaroid::TransactionSingleOp.new(conn = c)
66
+
67
+ (0..($_TEST_DATA.length - 1)).each do |i|
68
+ sc.write(@testTime.to_s + key + i.to_s, $_TEST_DATA[i])
69
+ end
70
+
71
+ # now try to delete the data:
72
+ (0..($_TEST_DATA.length - 1)).each do |i|
73
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
74
+ assert_equal(4, ok)
75
+ results = rdht.get_last_delete_result()
76
+ assert_equal(4, results.ok)
77
+ assert_equal(0, results.locks_set)
78
+ assert_equal(0, results.undefined)
79
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
80
+
81
+ # try again (should be successful with 0 deletes)
82
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
83
+ assert_equal(0, ok)
84
+ results = rdht.get_last_delete_result()
85
+ assert_equal(0, results.ok)
86
+ assert_equal(0, results.locks_set)
87
+ assert_equal(4, results.undefined)
88
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
89
+ end
90
+
91
+ c.close()
92
+ end
93
+
94
+ # Test method for ReplicatedDHT.delete(key) and TransactionSingleOp#write(key, value=str()).
95
+ # Inserts some values, tries to delete them afterwards, inserts them again and tries to delete them again (twice).
96
+ def test_delete2()
97
+ key = "_Delete2"
98
+ c = Scalaroid::JSONConnection.new(url = Scalaroid::DEFAULT_URL)
99
+ rdht = Scalaroid::ReplicatedDHT.new(conn = c)
100
+ sc = Scalaroid::TransactionSingleOp.new(conn = c)
101
+
102
+ (0..($_TEST_DATA.length - 1)).each do |i|
103
+ sc.write(@testTime.to_s + key + i.to_s, $_TEST_DATA[i])
104
+ end
105
+
106
+ # now try to delete the data:
107
+ (0..($_TEST_DATA.length - 1)).each do |i|
108
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
109
+ assert_equal(4, ok)
110
+ results = rdht.get_last_delete_result()
111
+ assert_equal(4, results.ok)
112
+ assert_equal(0, results.locks_set)
113
+ assert_equal(0, results.undefined)
114
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
115
+ end
116
+
117
+ (0..($_TEST_DATA.length - 1)).each do |i|
118
+ sc.write(@testTime.to_s + key + i.to_s, $_TEST_DATA[i])
119
+ end
120
+
121
+ # now try to delete the data:
122
+ (0..($_TEST_DATA.length - 1)).each do |i|
123
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
124
+ assert_equal(4, ok)
125
+ results = rdht.get_last_delete_result()
126
+ assert_equal(4, results.ok)
127
+ assert_equal(0, results.locks_set)
128
+ assert_equal(0, results.undefined)
129
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
130
+
131
+ # try again (should be successful with 0 deletes)
132
+ ok = rdht.delete(@testTime.to_s + key + i.to_s)
133
+ assert_equal(0, ok)
134
+ results = rdht.get_last_delete_result()
135
+ assert_equal(0, results.ok)
136
+ assert_equal(0, results.locks_set)
137
+ assert_equal(4, results.undefined)
138
+ _checkKeyDoesNotExist(@testTime.to_s + key + i.to_s)
139
+ end
140
+
141
+ c.close()
142
+ end
143
+ end