scalaroid 0.0.1

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.
@@ -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