libcouchbase-mapo 1.4.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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +38 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +445 -0
  9. data/Rakefile +76 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +19 -0
  12. data/lib/libcouchbase.rb +40 -0
  13. data/lib/libcouchbase/bucket.rb +825 -0
  14. data/lib/libcouchbase/callbacks.rb +69 -0
  15. data/lib/libcouchbase/connection.rb +886 -0
  16. data/lib/libcouchbase/design_docs.rb +92 -0
  17. data/lib/libcouchbase/error.rb +68 -0
  18. data/lib/libcouchbase/ext/libcouchbase.rb +1175 -0
  19. data/lib/libcouchbase/ext/libcouchbase/cmdbase.rb +23 -0
  20. data/lib/libcouchbase/ext/libcouchbase/cmdcounter.rb +36 -0
  21. data/lib/libcouchbase/ext/libcouchbase/cmdendure.rb +26 -0
  22. data/lib/libcouchbase/ext/libcouchbase/cmdfts.rb +24 -0
  23. data/lib/libcouchbase/ext/libcouchbase/cmdget.rb +30 -0
  24. data/lib/libcouchbase/ext/libcouchbase/cmdgetreplica.rb +49 -0
  25. data/lib/libcouchbase/ext/libcouchbase/cmdhttp.rb +58 -0
  26. data/lib/libcouchbase/ext/libcouchbase/cmdn1ql.rb +40 -0
  27. data/lib/libcouchbase/ext/libcouchbase/cmdobseqno.rb +33 -0
  28. data/lib/libcouchbase/ext/libcouchbase/cmdobserve.rb +30 -0
  29. data/lib/libcouchbase/ext/libcouchbase/cmdstore.rb +40 -0
  30. data/lib/libcouchbase/ext/libcouchbase/cmdstoredur.rb +45 -0
  31. data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +61 -0
  32. data/lib/libcouchbase/ext/libcouchbase/cmdverbosity.rb +29 -0
  33. data/lib/libcouchbase/ext/libcouchbase/cmdviewquery.rb +61 -0
  34. data/lib/libcouchbase/ext/libcouchbase/contigbuf.rb +14 -0
  35. data/lib/libcouchbase/ext/libcouchbase/create_st.rb +15 -0
  36. data/lib/libcouchbase/ext/libcouchbase/create_st0.rb +23 -0
  37. data/lib/libcouchbase/ext/libcouchbase/create_st1.rb +26 -0
  38. data/lib/libcouchbase/ext/libcouchbase/create_st2.rb +32 -0
  39. data/lib/libcouchbase/ext/libcouchbase/create_st3.rb +26 -0
  40. data/lib/libcouchbase/ext/libcouchbase/crst_u.rb +20 -0
  41. data/lib/libcouchbase/ext/libcouchbase/durability_opts_st_v.rb +11 -0
  42. data/lib/libcouchbase/ext/libcouchbase/durability_opts_t.rb +14 -0
  43. data/lib/libcouchbase/ext/libcouchbase/durabilityopt_sv0.rb +63 -0
  44. data/lib/libcouchbase/ext/libcouchbase/enums.rb +1007 -0
  45. data/lib/libcouchbase/ext/libcouchbase/fragbuf.rb +18 -0
  46. data/lib/libcouchbase/ext/libcouchbase/ftshandle.rb +7 -0
  47. data/lib/libcouchbase/ext/libcouchbase/histogram.rb +34 -0
  48. data/lib/libcouchbase/ext/libcouchbase/http_request_t.rb +7 -0
  49. data/lib/libcouchbase/ext/libcouchbase/keybuf.rb +20 -0
  50. data/lib/libcouchbase/ext/libcouchbase/multicmd_ctx.rb +30 -0
  51. data/lib/libcouchbase/ext/libcouchbase/mutation_token.rb +17 -0
  52. data/lib/libcouchbase/ext/libcouchbase/n1qlhandle.rb +7 -0
  53. data/lib/libcouchbase/ext/libcouchbase/n1qlparams.rb +7 -0
  54. data/lib/libcouchbase/ext/libcouchbase/respbase.rb +29 -0
  55. data/lib/libcouchbase/ext/libcouchbase/respcounter.rb +32 -0
  56. data/lib/libcouchbase/ext/libcouchbase/respendure.rb +49 -0
  57. data/lib/libcouchbase/ext/libcouchbase/respfts.rb +40 -0
  58. data/lib/libcouchbase/ext/libcouchbase/respget.rb +44 -0
  59. data/lib/libcouchbase/ext/libcouchbase/resphttp.rb +48 -0
  60. data/lib/libcouchbase/ext/libcouchbase/respmcversion.rb +38 -0
  61. data/lib/libcouchbase/ext/libcouchbase/respn1ql.rb +41 -0
  62. data/lib/libcouchbase/ext/libcouchbase/respobseqno.rb +52 -0
  63. data/lib/libcouchbase/ext/libcouchbase/respobserve.rb +41 -0
  64. data/lib/libcouchbase/ext/libcouchbase/respserverbase.rb +32 -0
  65. data/lib/libcouchbase/ext/libcouchbase/respstats.rb +38 -0
  66. data/lib/libcouchbase/ext/libcouchbase/respstore.rb +32 -0
  67. data/lib/libcouchbase/ext/libcouchbase/respstoredur.rb +38 -0
  68. data/lib/libcouchbase/ext/libcouchbase/respsubdoc.rb +35 -0
  69. data/lib/libcouchbase/ext/libcouchbase/respviewquery.rb +67 -0
  70. data/lib/libcouchbase/ext/libcouchbase/sdentry.rb +22 -0
  71. data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +31 -0
  72. data/lib/libcouchbase/ext/libcouchbase/t.rb +7 -0
  73. data/lib/libcouchbase/ext/libcouchbase/valbuf.rb +22 -0
  74. data/lib/libcouchbase/ext/libcouchbase/valbuf_u_buf.rb +14 -0
  75. data/lib/libcouchbase/ext/libcouchbase/viewhandle.rb +7 -0
  76. data/lib/libcouchbase/ext/libcouchbase_libuv.rb +22 -0
  77. data/lib/libcouchbase/ext/tasks.rb +39 -0
  78. data/lib/libcouchbase/n1ql.rb +78 -0
  79. data/lib/libcouchbase/query_full_text.rb +147 -0
  80. data/lib/libcouchbase/query_n1ql.rb +123 -0
  81. data/lib/libcouchbase/query_view.rb +135 -0
  82. data/lib/libcouchbase/results_fiber.rb +281 -0
  83. data/lib/libcouchbase/results_native.rb +220 -0
  84. data/lib/libcouchbase/subdoc_request.rb +139 -0
  85. data/lib/libcouchbase/version.rb +5 -0
  86. data/libcouchbase.gemspec +68 -0
  87. data/spec/bucket_spec.rb +290 -0
  88. data/spec/connection_spec.rb +257 -0
  89. data/spec/design_docs_spec.rb +31 -0
  90. data/spec/error_spec.rb +26 -0
  91. data/spec/fts_spec.rb +135 -0
  92. data/spec/n1ql_spec.rb +206 -0
  93. data/spec/results_libuv_spec.rb +244 -0
  94. data/spec/results_native_spec.rb +259 -0
  95. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/design.json +1 -0
  96. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/data-0000.cbb +0 -0
  97. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/failover.json +1 -0
  98. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/meta.json +1 -0
  99. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/seqno.json +1 -0
  100. data/spec/seed/2016-10-25T043505Z/2016-10-25T043505Z-full/bucket-default/node-127.0.0.1%3A8091/snapshot_markers.json +1 -0
  101. data/spec/subdoc_spec.rb +192 -0
  102. data/spec/view_spec.rb +201 -0
  103. data/windows_build.md +36 -0
  104. metadata +265 -0
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ module Libcouchbase; end;
4
+ class Libcouchbase::SubdocRequest
5
+
6
+ def initialize(key, quiet, bucket: nil, exec_opts: nil)
7
+ @key = key.to_s
8
+ raise ArgumentError.new("invalid document key #{key.inspect}") unless @key.length > 0
9
+ @refs = []
10
+ @mode = nil
11
+ @quiet = quiet
12
+ @specs = []
13
+ @ignore = []
14
+
15
+ @bucket = bucket
16
+ @exec_opts = exec_opts
17
+ end
18
+
19
+ attr_reader :mode, :key, :ignore
20
+
21
+ # Internal use only
22
+ def to_specs_array
23
+ return @mem if @mem # effectively freezes this object
24
+ number = @specs.length
25
+ @mem = FFI::MemoryPointer.new(::Libcouchbase::Ext::SDSPEC, number, false)
26
+ @specs.each_with_index do |spec, index|
27
+ struct_bytes = spec.to_ptr.get_bytes(0, ::Libcouchbase::Ext::SDSPEC.size) # (offset, length)
28
+ @mem[index].put_bytes(0, struct_bytes) # (offset, byte_string)
29
+ end
30
+ @specs = nil
31
+ [@mem, number]
32
+ end
33
+
34
+ # Internal use only
35
+ def free_memory
36
+ @refs = nil
37
+ @mem = nil
38
+ end
39
+
40
+ # When not used in block form
41
+ def execute!(**opts)
42
+ opts = @exec_opts.merge(opts)
43
+ @exec_opts = nil
44
+ bucket = @bucket
45
+ @bucket = nil
46
+ bucket.subdoc_execute!(self, **opts)
47
+ end
48
+
49
+
50
+ # =========
51
+ # Lookups
52
+ # =========
53
+
54
+ [ :get, :exists, :get_count ].each do |cmd|
55
+ command = :"sdcmd_#{cmd}"
56
+ define_method cmd do |path, quiet: nil, **opts|
57
+ quiet = @quiet if quiet.nil?
58
+ new_spec(quiet, path, command, :lookup)
59
+ self
60
+ end
61
+ end
62
+ alias_method :exists?, :exists
63
+
64
+
65
+ # ===========
66
+ # Mutations
67
+ # ===========
68
+
69
+ def remove(path, quiet: nil, **opts)
70
+ quiet = @quiet if quiet.nil?
71
+ new_spec(quiet, path, :sdcmd_remove, :mutate)
72
+ self
73
+ end
74
+
75
+ [
76
+ :dict_add, :dict_upsert, :array_add_first, :array_add_last, :array_add_unique, :counter
77
+ ].each do |cmd|
78
+ command = :"sdcmd_#{cmd}"
79
+ define_method cmd do |path, value, create_intermediates: true, **opts|
80
+ spec = new_spec(false, path, command, :mutate, create_intermediates)
81
+ set_value(spec, value)
82
+ self
83
+ end
84
+ end
85
+
86
+ [
87
+ :replace, :array_insert
88
+ ].each do |cmd|
89
+ command = :"sdcmd_#{cmd}"
90
+ define_method cmd do |path, value, **opts|
91
+ spec = new_spec(false, path, command, :mutate, false)
92
+ set_value(spec, value)
93
+ self
94
+ end
95
+ end
96
+
97
+
98
+ protected
99
+
100
+
101
+ # http://docs.couchbase.com/sdk-api/couchbase-c-client-2.8.2/group__lcb-subdoc.html#ga53e89dd6b480e81b82fb305d04d92e18
102
+ def new_spec(quiet, path, cmd, mode, create_intermediates = false)
103
+ @mode ||= mode
104
+ raise "unable to perform #{cmd} as mode is currently #{@mode}" if @mode != mode
105
+
106
+ spec = ::Libcouchbase::Ext::SDSPEC.new
107
+ spec[:sdcmd] = ::Libcouchbase::Ext::SUBDOCOP[cmd]
108
+ spec[:options] = ::Libcouchbase::Ext::SDSPEC::MKINTERMEDIATES if create_intermediates
109
+
110
+ loc = path.to_s
111
+ str = ref(loc)
112
+ spec[:path][:type] = :kv_copy
113
+ spec[:path][:contig][:bytes] = str
114
+ spec[:path][:contig][:nbytes] = loc.bytesize
115
+
116
+ @ignore << quiet
117
+ @specs << spec
118
+ spec
119
+ end
120
+
121
+ # http://docs.couchbase.com/sdk-api/couchbase-c-client-2.8.2/group__lcb-subdoc.html#ga61009762f6b23ae2a9685ddb888dc406
122
+ def set_value(spec, value)
123
+ # Create a JSON version of the value.
124
+ # We throw it into an array so strings and numbers etc are valid, then we remove the array.
125
+ val = [value].to_json[1...-1]
126
+ str = ref(val)
127
+ spec[:value][:vtype] = :kv_copy
128
+ spec[:value][:u_buf][:contig][:bytes] = str
129
+ spec[:value][:u_buf][:contig][:nbytes] = val.bytesize
130
+ value
131
+ end
132
+
133
+ # We need to hold a reference to c-strings so they are not GC'd
134
+ def ref(string)
135
+ str = ::FFI::MemoryPointer.from_string(string)
136
+ @refs << str
137
+ str
138
+ end
139
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ module Libcouchbase
4
+ VERSION = '1.4.1'
5
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path("../lib/libcouchbase/version", __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "libcouchbase-mapo"
5
+ gem.version = Libcouchbase::VERSION
6
+ gem.license = 'MIT'
7
+ gem.authors = ["Stephen von Takach"]
8
+ gem.email = ["steve@cotag.me"]
9
+ gem.homepage = "https://github.com/cotag/libcouchbase"
10
+ gem.summary = "libcouchbase bindings for Ruby"
11
+ gem.description = "A wrapper around libcouchbase for Ruby"
12
+
13
+ gem.extensions << "ext/Rakefile"
14
+
15
+ gem.required_ruby_version = '>= 2.1.0'
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_runtime_dependency 'ffi', '~> 1.9'
19
+ gem.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
20
+ gem.add_runtime_dependency 'libuv', '>= 3.2.2', '< 5'
21
+
22
+ gem.add_development_dependency 'rake', '~> 11.2'
23
+ gem.add_development_dependency 'rspec', '~> 3.5'
24
+ gem.add_development_dependency 'yard', '~> 0.9'
25
+ gem.add_development_dependency 'uv-rays', '~> 2.0' # for libuv results spec
26
+ gem.add_development_dependency 'em-synchrony', '~> 1.0' # for eventmachine spec
27
+
28
+ # https://github.com/stakach/ffi-gen
29
+ # gem.add_development_dependency 'ffi-gen'
30
+
31
+ gem.files = `git ls-files`.split("\n")
32
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
33
+
34
+ if File.exist? 'ext/libcouchbase.dll'
35
+ gem.files += ['ext/libcouchbase.dll', 'ext/libcouchbase_libuv.dll']
36
+ end
37
+
38
+ # Add the submodule to the gem
39
+ relative_path = File.expand_path("../", __FILE__) + '/'
40
+ `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
41
+
42
+ if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
43
+ # Detect if cygwin path is being used by git
44
+ submodule_path = submodule_path[1..-1]
45
+ submodule_path.insert(1, ':')
46
+ end
47
+
48
+ # for each submodule, change working directory to that submodule
49
+ Dir.chdir(submodule_path) do
50
+ # Make the submodule path relative
51
+ submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
52
+
53
+ # issue git ls-files in submodule's directory
54
+ submodule_files = `git ls-files`.split($\)
55
+
56
+ # prepend the submodule path to create relative file paths
57
+ submodule_files_paths = submodule_files.map do |filename|
58
+ File.join(submodule_path, filename)
59
+ end
60
+
61
+ # add relative paths to gem.files
62
+ gem.files += submodule_files_paths
63
+ end
64
+ end
65
+
66
+ # Remove sym link (blows up on windows)
67
+ gem.files.delete('ext/libcouchbase/configure.pl')
68
+ end
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true, encoding: ASCII-8BIT
2
+
3
+ require 'libcouchbase'
4
+ Libcouchbase::Defaults.username = 'tester'
5
+ Libcouchbase::Defaults.password = 'password123'
6
+
7
+ describe Libcouchbase::Bucket do
8
+ before :each do
9
+ # This will load the couchbase connection on a different thread
10
+ @bucket = Libcouchbase::Bucket.new
11
+ @reactor = ::Libuv::Reactor.default
12
+ @log = []
13
+ end
14
+
15
+ after :each do
16
+ @bucket = nil
17
+ @reactor = nil
18
+ @log = nil
19
+ end
20
+
21
+ describe 'reactor loop' do
22
+ it "should set a value" do
23
+ @reactor.run { |reactor|
24
+ result = @bucket.set('somekey', 'woop woop')
25
+ @log << result.key
26
+ @log << result.value
27
+ @log << @bucket.set('somekey2', 'woop woop2').value
28
+ }
29
+
30
+ expect(@log).to eq(['somekey', 'woop woop', 'woop woop2'])
31
+ end
32
+
33
+ it "should get a value" do
34
+ @reactor.run { |reactor|
35
+ @log << @bucket.get('somekey')
36
+ @log << @bucket.get('somekey', extended: true).value
37
+ }
38
+ expect(@log).to eq(['woop woop', 'woop woop'])
39
+ end
40
+
41
+ it "should get a value quietly" do
42
+ @reactor.run { |reactor|
43
+ @log << @bucket.get('somekey-noexist', quiet: true)
44
+ @log << @bucket[:noexist2]
45
+ }
46
+ expect(@log).to eq([nil, nil])
47
+ end
48
+
49
+ it "should get multiple values" do
50
+ @reactor.run { |reactor|
51
+ @log << @bucket.get('somekey', 'somekey2')
52
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true)
53
+ }
54
+ expect(@log).to eq([['woop woop', 'woop woop2'], ['woop woop', 'woop woop2', nil]])
55
+ end
56
+
57
+ it "should get multiple values as a hash" do
58
+ @reactor.run { |reactor|
59
+ @log << @bucket.get('somekey', 'somekey2', assemble_hash: true)
60
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true, assemble_hash: true)
61
+ @log << @bucket.get('somekey', assemble_hash: true)
62
+ @log << @bucket.get('no-exist-sgs', quiet: true, assemble_hash: true)
63
+ }
64
+ expect(@log).to eq([
65
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2'},
66
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2', 'no-exist-sgs' => nil},
67
+ {'somekey' => 'woop woop'},
68
+ {'no-exist-sgs' => nil}
69
+ ])
70
+ end
71
+
72
+ it "should compare and swap a value" do
73
+ @reactor.run { |reactor|
74
+ @bucket.set('somekey', 'woop woop')
75
+ result = @bucket.cas('somekey') do |current|
76
+ @log << current
77
+ "current #{current}"
78
+ end
79
+ @log << result.value
80
+ }
81
+ expect(@log).to eq(['woop woop', 'current woop woop'])
82
+ end
83
+
84
+ it "should fetch a value" do
85
+ @reactor.run { |reactor|
86
+ @bucket.delete('randomunknown')
87
+ @log << @bucket.fetch('randomunknown', 'woop woop')
88
+ @log << @bucket.fetch('randomunknown') { 'testing' }
89
+
90
+ @bucket.delete('otherunknown')
91
+ @log << @bucket.fetch('otherunknown') { 'testing' }
92
+ @log << @bucket.fetch('otherunknown', 'woop woop')
93
+ }
94
+ expect(@log).to eq(['woop woop', 'woop woop', 'testing', 'testing'])
95
+ end
96
+
97
+ it "should retry when performing a CAS operation" do
98
+ @reactor.run { |reactor|
99
+ begin
100
+ @bucket.set('somekey', 'woop woop')
101
+ result = @bucket.cas('somekey', retry: 2) do |current|
102
+ @log << current
103
+ # This ensures the operation fails
104
+ @bucket.set('somekey', 'woop woop1')
105
+ "current #{current}"
106
+ end
107
+ @log << result.value
108
+ rescue Libcouchbase::Error::KeyExists
109
+ @log << :error
110
+ end
111
+ }
112
+ expect(@log).to eq(['woop woop', 'woop woop1', 'woop woop1', :error])
113
+ end
114
+ end
115
+
116
+ describe 'native ruby' do
117
+ it "should set a value" do
118
+ result = @bucket.set('somekey', 'woop woop')
119
+ @log << result.key
120
+ @log << result.value
121
+ @log << @bucket.set('somekey2', 'woop woop2').value
122
+
123
+ expect(@log).to eq(['somekey', 'woop woop', 'woop woop2'])
124
+ end
125
+
126
+ it "should get a value" do
127
+ @log << @bucket.get('somekey')
128
+ @log << @bucket.get('somekey', extended: true).value
129
+
130
+ expect(@log).to eq(['woop woop', 'woop woop'])
131
+ end
132
+
133
+ it "should get a value quietly" do
134
+ @log << @bucket.get('somekey-noexist', quiet: true)
135
+ @log << @bucket[:noexist2]
136
+
137
+ expect(@log).to eq([nil, nil])
138
+ end
139
+
140
+ it "should get multiple values" do
141
+ @log << @bucket.get('somekey', 'somekey2')
142
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true)
143
+
144
+ expect(@log).to eq([['woop woop', 'woop woop2'], ['woop woop', 'woop woop2', nil]])
145
+ end
146
+
147
+ it "should get multiple values as a hash" do
148
+ @log << @bucket.get('somekey', 'somekey2', assemble_hash: true)
149
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true, assemble_hash: true)
150
+ @log << @bucket.get('somekey', assemble_hash: true)
151
+ @log << @bucket.get('no-exist-sgs', quiet: true, assemble_hash: true)
152
+
153
+ expect(@log).to eq([
154
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2'},
155
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2', 'no-exist-sgs' => nil},
156
+ {'somekey' => 'woop woop'},
157
+ {'no-exist-sgs' => nil}
158
+ ])
159
+ end
160
+
161
+ it "should get multiple results asynchronously and then wait for the results" do
162
+ results = []
163
+ results << @bucket.get('somekey', async: true)
164
+ results << @bucket.get('somekey2', async: true)
165
+
166
+ @log = @bucket.wait_results results
167
+
168
+ expect(@log).to eq(['woop woop', 'woop woop2'])
169
+ end
170
+
171
+ it "should compare and swap a value" do
172
+ @bucket.set('somekey', 'woop woop')
173
+ result = @bucket.cas('somekey') do |current|
174
+ @log << current
175
+ "current #{current}"
176
+ end
177
+ @log << result.value
178
+
179
+ expect(@log).to eq(['woop woop', 'current woop woop'])
180
+ end
181
+
182
+ it "should retry when performing a CAS operation" do
183
+ begin
184
+ @bucket.set('somekey', 'woop woop')
185
+ result = @bucket.cas('somekey', retry: 2) do |current|
186
+ @log << current
187
+ # This ensures the operation fails
188
+ @bucket.set('somekey', 'woop woop1')
189
+ "current #{current}"
190
+ end
191
+ @log << result.value
192
+ rescue Libcouchbase::Error::KeyExists
193
+ @log << :error
194
+ end
195
+
196
+ expect(@log).to eq(['woop woop', 'woop woop1', 'woop woop1', :error])
197
+ end
198
+ end
199
+
200
+ describe 'eventmachine loop' do
201
+ require 'em-synchrony'
202
+
203
+ it "should set a value" do
204
+ EM.synchrony {
205
+ result = @bucket.set('somekey', 'woop woop')
206
+ @log << result.key
207
+ @log << result.value
208
+ @log << @bucket.set('somekey2', 'woop woop2').value
209
+ EM.stop
210
+ }
211
+
212
+ expect(@log).to eq(['somekey', 'woop woop', 'woop woop2'])
213
+ end
214
+
215
+ it "should get a value" do
216
+ EM.synchrony {
217
+ @log << @bucket.get('somekey')
218
+ @log << @bucket.get('somekey', extended: true).value
219
+ EM.stop
220
+ }
221
+ expect(@log).to eq(['woop woop', 'woop woop'])
222
+ end
223
+
224
+ it "should get a value quietly" do
225
+ EM.synchrony {
226
+ @log << @bucket.get('somekey-noexist', quiet: true)
227
+ @log << @bucket[:noexist2]
228
+ EM.stop
229
+ }
230
+ expect(@log).to eq([nil, nil])
231
+ end
232
+
233
+ it "should get multiple values" do
234
+ EM.synchrony {
235
+ @log << @bucket.get('somekey', 'somekey2')
236
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true)
237
+ EM.stop
238
+ }
239
+ expect(@log).to eq([['woop woop', 'woop woop2'], ['woop woop', 'woop woop2', nil]])
240
+ end
241
+
242
+ it "should get multiple values as a hash" do
243
+ EM.synchrony {
244
+ @log << @bucket.get('somekey', 'somekey2', assemble_hash: true)
245
+ @log << @bucket.get('somekey', 'somekey2', 'no-exist-sgs', quiet: true, assemble_hash: true)
246
+ @log << @bucket.get('somekey', assemble_hash: true)
247
+ @log << @bucket.get('no-exist-sgs', quiet: true, assemble_hash: true)
248
+ EM.stop
249
+ }
250
+ expect(@log).to eq([
251
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2'},
252
+ {'somekey' => 'woop woop', 'somekey2' => 'woop woop2', 'no-exist-sgs' => nil},
253
+ {'somekey' => 'woop woop'},
254
+ {'no-exist-sgs' => nil}
255
+ ])
256
+ end
257
+
258
+ it "should compare and swap a value" do
259
+ EM.synchrony {
260
+ @bucket.set('somekey', 'woop woop')
261
+ result = @bucket.cas('somekey') do |current|
262
+ @log << current
263
+ "current #{current}"
264
+ end
265
+ @log << result.value
266
+ EM.stop
267
+ }
268
+ expect(@log).to eq(['woop woop', 'current woop woop'])
269
+ end
270
+
271
+ it "should retry when performing a CAS operation" do
272
+ EM.synchrony {
273
+ begin
274
+ @bucket.set('somekey', 'woop woop')
275
+ result = @bucket.cas('somekey', retry: 2) do |current|
276
+ @log << current
277
+ # This ensures the operation fails
278
+ @bucket.set('somekey', 'woop woop1')
279
+ "current #{current}"
280
+ end
281
+ @log << result.value
282
+ rescue Libcouchbase::Error::KeyExists
283
+ @log << :error
284
+ end
285
+ EM.stop
286
+ }
287
+ expect(@log).to eq(['woop woop', 'woop woop1', 'woop woop1', :error])
288
+ end
289
+ end
290
+ end