fauna 1.3.4 → 2.0.0

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,58 @@
1
+ module Fauna
2
+ # The result of a request. Provided to observers and included within errors.
3
+ class RequestResult
4
+ # The Client.
5
+ attr_reader :client
6
+ # HTTP method. Either +:get+, +:post+, +:put+, +:patch+, or +:delete+
7
+ attr_reader :method
8
+ # Path that was queried. Relative to client's domain.
9
+ attr_reader :path
10
+ # URL query. +nil+ except for +GET+ requests.
11
+ attr_reader :query
12
+ # Request data.
13
+ attr_reader :request_content
14
+ # String value returned by the server.
15
+ attr_reader :response_raw
16
+ ##
17
+ # Parsed value returned by the server.
18
+ # Includes "resource" wrapper hash, or may be an "errors" hash instead.
19
+ # In the case of a JSON parse error, this will be nil.
20
+ attr_reader :response_content
21
+ # HTTP status code.
22
+ attr_reader :status_code
23
+ # A hash of headers.
24
+ attr_reader :response_headers
25
+ # Time the request started.
26
+ attr_reader :start_time
27
+ # Time the response was received.
28
+ attr_reader :end_time
29
+
30
+ def initialize(
31
+ client,
32
+ method, path, query, request_content,
33
+ response_raw, response_content, status_code, response_headers,
34
+ start_time, end_time) # :nodoc:
35
+ @client = client
36
+ @method = method
37
+ @path = path
38
+ @query = query
39
+ @request_content = request_content
40
+ @response_raw = response_raw
41
+ @response_content = response_content
42
+ @status_code = status_code
43
+ @response_headers = response_headers
44
+ @start_time = start_time
45
+ @end_time = end_time
46
+ end
47
+
48
+ # Real time spent performing the request.
49
+ def time_taken
50
+ end_time - start_time
51
+ end
52
+
53
+ # Credentials used by the client.
54
+ def auth
55
+ client.credentials
56
+ end
57
+ end
58
+ end
@@ -1,9 +1,50 @@
1
1
  module Fauna
2
+ ##
3
+ # Converts microseconds to a Time object.
4
+ #
5
+ # +microseconds+:: Time in microseconds.
2
6
  def self.time_from_usecs(microseconds)
3
7
  Time.at(microseconds / 1_000_000, microseconds % 1_000_000)
4
8
  end
5
9
 
10
+ ##
11
+ # Converts a Time object to microseconds.
12
+ #
13
+ # +time+:: A Time object.
6
14
  def self.usecs_from_time(time)
7
15
  time.to_i * 1_000_000 + time.usec
8
16
  end
17
+
18
+ class DSLContext # :nodoc:
19
+ def self.eval_dsl(dsl, &blk)
20
+ ctx = eval('self', blk.binding)
21
+ dsl.instance_variable_set(:@__ctx__, ctx)
22
+
23
+ ctx.instance_variables.each do |iv|
24
+ dsl.instance_variable_set(iv, ctx.instance_variable_get(iv))
25
+ end
26
+
27
+ dsl.instance_exec(&blk)
28
+
29
+ ensure
30
+ dsl.instance_variables.each do |iv|
31
+ if iv.to_sym != :@__ctx__
32
+ ctx.instance_variable_set(iv, dsl.instance_variable_get(iv))
33
+ end
34
+ end
35
+ end
36
+
37
+ NON_PROXIED_METHODS = Set.new %w(__send__ object_id __id__ == equal?
38
+ ! != instance_exec instance_variables
39
+ instance_variable_get instance_variable_set
40
+ ).map(&:to_sym)
41
+
42
+ instance_methods.each do |method|
43
+ undef_method(method) unless NON_PROXIED_METHODS.include?(method.to_sym)
44
+ end
45
+
46
+ def method_missing(method, *args, &block)
47
+ @__ctx__.send(method, *args, &block)
48
+ end
49
+ end
9
50
  end
@@ -0,0 +1,4 @@
1
+ module Fauna
2
+ # The version of the Fauna gem
3
+ VERSION = '2.0.0'
4
+ end
@@ -0,0 +1,73 @@
1
+ RSpec.describe Fauna::ClientLogger do
2
+ before(:all) do
3
+ create_test_db
4
+ @test_class = client.post('classes', name: 'logger_test')[:ref]
5
+ end
6
+
7
+ after(:all) do
8
+ destroy_test_db
9
+ end
10
+
11
+ # Captures logger output from wrapped client and splits it into lines
12
+ def capture_log
13
+ lines = nil
14
+ observer = Fauna::ClientLogger.logger { |log| lines = log.split("\n") }
15
+
16
+ yield get_client(secret: @server_secret, observer: observer)
17
+
18
+ lambda { lines.shift }
19
+ end
20
+
21
+ it 'logs response' do
22
+ reader = capture_log do |client|
23
+ expect(client.ping).to eq('Scope global is OK')
24
+ end
25
+
26
+ expect(reader.call).to eq('Fauna GET /ping')
27
+ expect(reader.call).to match(/^ Credentials:/)
28
+ expect(reader.call).to eq(' Response headers: {')
29
+
30
+ # Skip through headers
31
+ loop do
32
+ line = reader.call
33
+ unless line.start_with? ' '
34
+ expect(line).to eq(' }')
35
+ break
36
+ end
37
+ end
38
+
39
+ expect(reader.call).to eq(' Response JSON: {')
40
+ expect(reader.call).to eq(' "resource": "Scope global is OK"')
41
+ expect(reader.call).to eq(' }')
42
+ expect(reader.call).to match(/^ Response \(200\): Network latency \d+ms$/)
43
+ end
44
+
45
+ it 'logs request content' do
46
+ value = random_number
47
+ reader = capture_log do |client|
48
+ client.post @test_class, data: { a: value }
49
+ end
50
+
51
+ expect(reader.call).to eq("Fauna POST /#{@test_class}")
52
+ expect(reader.call).to match(/^ Credentials:/)
53
+ expect(reader.call).to eq(' Request JSON: {')
54
+ expect(reader.call).to eq(' "data": {')
55
+ expect(reader.call).to eq(" \"a\": #{value}")
56
+ expect(reader.call).to eq(' }')
57
+ expect(reader.call).to eq(' }')
58
+ # Ignore the rest
59
+ end
60
+
61
+ it 'logs request query' do
62
+ instance = client.post(@test_class)
63
+ ref = instance[:ref]
64
+ ts = instance[:ts]
65
+
66
+ reader = capture_log do |client|
67
+ client.get ref, ts: ts
68
+ end
69
+
70
+ expect(reader.call).to eq("Fauna GET /#{ref}?ts=#{ts}")
71
+ # Ignore the rest
72
+ end
73
+ end
@@ -0,0 +1,202 @@
1
+ RSpec.describe Fauna::Client do
2
+ before(:all) do
3
+ create_test_db
4
+ @test_class = client.post('classes', name: 'client_test')[:ref]
5
+ end
6
+
7
+ after(:all) do
8
+ destroy_test_db
9
+ end
10
+
11
+ describe 'connection' do
12
+ # Compress string with gzip
13
+ def gzipped(str)
14
+ out = ''
15
+ StringIO.open out do |io|
16
+ writer = Zlib::GzipWriter.new io
17
+ writer.write str
18
+ writer.flush
19
+ writer.close
20
+ end
21
+ out
22
+ end
23
+
24
+ it 'decodes gzip response' do
25
+ response = gzipped '{"resource": 1}'
26
+ test_client = stub_client(:get, 'tests/decode', response, 'Content-Encoding' => 'gzip')
27
+ expect(test_client.get('tests/decode')).to be(1)
28
+ end
29
+
30
+ it 'decodes deflate response' do
31
+ response = Zlib::Deflate.deflate '{"resource": 1}'
32
+ test_client = stub_client(:get, 'tests/decode', response, 'Content-Encoding' => 'deflate')
33
+ expect(test_client.get('tests/decode')).to be(1)
34
+ end
35
+ end
36
+
37
+ describe 'serialization' do
38
+ it 'decodes ref' do
39
+ ref = Fauna::Ref.new('classes', random_string, random_number)
40
+ test_client = stub_client(:get, 'tests/ref', to_json(resource: ref))
41
+
42
+ response = test_client.get('tests/ref')
43
+ expect(response).to be_a(Fauna::Ref)
44
+ expect(response).to eq(ref)
45
+ end
46
+
47
+ it 'decodes set' do
48
+ set = Fauna::SetRef.new(match: random_string, index: Fauna::Ref.new('indexes', random_string))
49
+ test_client = stub_client(:get, 'tests/set', to_json(resource: set))
50
+
51
+ response = test_client.get('tests/set')
52
+ expect(response).to be_a(Fauna::SetRef)
53
+ expect(response).to eq(set)
54
+ end
55
+
56
+ it 'decodes obj' do
57
+ data = { random_string.to_sym => random_string }
58
+ obj = { :@obj => data }
59
+ test_client = stub_client(:get, 'tests/obj', to_json(resource: obj))
60
+
61
+ response = test_client.get('tests/obj')
62
+ expect(response).to be_a(Hash)
63
+ expect(response).to eq(data)
64
+ end
65
+
66
+ it 'decodes ts' do
67
+ ts = Time.at(0).utc
68
+ test_client = stub_client(:get, 'tests/ts', to_json(resource: ts))
69
+
70
+ response = test_client.get('tests/ts')
71
+ expect(response).to be_a(Time)
72
+ expect(response).to eq(ts)
73
+ end
74
+
75
+ it 'decodes date' do
76
+ date = Date.new(1970, 1, 1)
77
+ test_client = stub_client(:get, 'tests/date', to_json(resource: date))
78
+
79
+ response = test_client.get('tests/date')
80
+ expect(response).to be_a(Date)
81
+ expect(response).to eq(date)
82
+ end
83
+ end
84
+
85
+ describe '#with_secret' do
86
+ it 'creates client with secret' do
87
+ old_secret = random_string
88
+ new_secret = random_string
89
+
90
+ old_client = get_client(secret: old_secret)
91
+ new_client = old_client.with_secret(new_secret)
92
+
93
+ expect(old_client.credentials).to eq([old_secret])
94
+ expect(new_client.credentials).to eq([new_secret])
95
+ end
96
+ end
97
+
98
+ describe '#query' do
99
+ it 'performs query from expression' do
100
+ value = random_number
101
+
102
+ instance = client.query(Fauna::Query.create(@test_class, data: { a: value }))
103
+
104
+ expect(instance[:class]).to eq(@test_class)
105
+ expect(instance[:data][:a]).to eq(value)
106
+ end
107
+
108
+ it 'performs query from block' do
109
+ value = random_number
110
+
111
+ instance = client.query { create @test_class, data: { a: value } }
112
+
113
+ expect(instance[:class]).to eq(@test_class)
114
+ expect(instance[:data][:a]).to eq(value)
115
+ end
116
+ end
117
+
118
+ describe '#get' do
119
+ it 'performs GET' do
120
+ value = random_number
121
+ ref = client.post(@test_class, data: { a: value })[:ref]
122
+
123
+ instance = client.get(ref)
124
+
125
+ expect(instance[:ref]).to eq(ref)
126
+ expect(instance[:data][:a]).to eq(value)
127
+ end
128
+
129
+ it 'performs GET with query' do
130
+ value = random_number
131
+ created = client.post(@test_class, data: { a: value })
132
+ ref = created[:ref]
133
+ ts = created[:ts]
134
+
135
+ instance = client.get(ref, ts: ts)
136
+
137
+ expect(instance[:ref]).to eq(ref)
138
+ expect(instance[:data][:a]).to eq(value)
139
+
140
+ expect { client.get(ref, ts: ts - 1) }.to raise_error(Fauna::NotFound)
141
+ end
142
+ end
143
+
144
+ describe '#post' do
145
+ it 'performs POST' do
146
+ value = random_number
147
+
148
+ instance = client.post(@test_class, data: { a: value })
149
+
150
+ expect(instance[:class]).to eq(@test_class)
151
+ expect(instance[:data][:a]).to eq(value)
152
+ end
153
+ end
154
+
155
+ describe '#put' do
156
+ it 'performs PUT' do
157
+ value = random_number
158
+ ref = client.post(@test_class, data: { a: random_number })[:ref]
159
+
160
+ instance = client.put(ref, data: { b: value })
161
+
162
+ expect(instance[:ref]).to eq(ref)
163
+ expect(instance[:data][:a]).to be_nil
164
+ expect(instance[:data][:b]).to eq(value)
165
+ end
166
+ end
167
+
168
+ describe '#patch' do
169
+ it 'performs PATCH' do
170
+ value1 = random_number
171
+ value2 = random_number
172
+ ref = client.post(@test_class, data: { a: value1 })[:ref]
173
+
174
+ instance = client.patch(ref, data: { b: value2 })
175
+
176
+ expect(instance[:ref]).to eq(ref)
177
+ expect(instance[:data][:a]).to eq(value1)
178
+ expect(instance[:data][:b]).to eq(value2)
179
+ end
180
+ end
181
+
182
+ describe '#delete' do
183
+ it 'performs DELETE' do
184
+ ref = client.post(@test_class, data: { a: random_number })[:ref]
185
+
186
+ instance = client.delete(ref)
187
+
188
+ expect(instance[:ref]).to eq(ref)
189
+ expect { client.get(ref) }.to raise_error(Fauna::NotFound)
190
+ end
191
+ end
192
+
193
+ describe '#ping' do
194
+ it 'performs ping' do
195
+ expect(client.ping).to eq('Scope global is OK')
196
+ end
197
+
198
+ it 'performs ping with scope' do
199
+ expect(client.ping(scope: 'node')).to eq('Scope node is OK')
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,121 @@
1
+ RSpec.describe Fauna::Context do
2
+ before(:all) do
3
+ create_test_db
4
+ @test_class = client.post('classes', name: 'context_test')[:ref]
5
+ end
6
+
7
+ after(:all) do
8
+ destroy_test_db
9
+ end
10
+
11
+ around do |ex|
12
+ # Ensure context is not shared between tests
13
+ Fauna::Context.reset
14
+ ex.run
15
+ Fauna::Context.reset
16
+ end
17
+
18
+ describe 'REST methods' do
19
+ around do |ex|
20
+ stubs = Faraday::Adapter::Test::Stubs.new
21
+ [:get, :post, :put, :patch, :delete].each do |method|
22
+ stubs.send(method, '/tests/context') do |env|
23
+ [200, {}, { resource: env.method.to_s.upcase }.to_json]
24
+ end
25
+ end
26
+
27
+ Fauna::Context.block(Fauna::Client.new(adapter: [:test, stubs])) do
28
+ ex.run
29
+ end
30
+ end
31
+
32
+ describe '#get' do
33
+ it 'performs GET request' do
34
+ expect(Fauna::Context.get('tests/context')).to eq('GET')
35
+ end
36
+ end
37
+
38
+ describe '#post' do
39
+ it 'performs POST request' do
40
+ expect(Fauna::Context.post('tests/context')).to eq('POST')
41
+ end
42
+ end
43
+
44
+ describe '#put' do
45
+ it 'performs PUT request' do
46
+ expect(Fauna::Context.put('tests/context')).to eq('PUT')
47
+ end
48
+ end
49
+
50
+ describe '#patch' do
51
+ it 'performs PATCH request' do
52
+ expect(Fauna::Context.patch('tests/context')).to eq('PATCH')
53
+ end
54
+ end
55
+
56
+ describe '#delete' do
57
+ it 'performs DELETE request' do
58
+ expect(Fauna::Context.delete('tests/context')).to eq('DELETE')
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '#query' do
64
+ it 'performs query' do
65
+ Fauna::Context.block(client) do
66
+ expect(Fauna::Context.query { add 1, 1 }).to eq(2)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#push' do
72
+ it 'pushes new client' do
73
+ new = Fauna::Client.new
74
+
75
+ Fauna::Context.push(new)
76
+ expect(Fauna::Context.client).to be(new)
77
+ end
78
+ end
79
+
80
+ describe '#pop' do
81
+ it 'pops active client' do
82
+ outer = Fauna::Client.new
83
+ inner = Fauna::Client.new
84
+
85
+ Fauna::Context.push(outer)
86
+ Fauna::Context.push(inner)
87
+
88
+ expect(Fauna::Context.pop).to be(inner)
89
+ expect(Fauna::Context.client).to be(outer)
90
+ end
91
+ end
92
+
93
+ describe '#reset' do
94
+ it 'resets stack' do
95
+ initial = Fauna::Client.new
96
+ outer = Fauna::Client.new
97
+ inner = Fauna::Client.new
98
+
99
+ Fauna::Context.push(initial)
100
+ Fauna::Context.push(outer)
101
+ Fauna::Context.push(inner)
102
+
103
+ Fauna::Context.reset
104
+ expect { Fauna::Context.client }.to raise_error(Fauna::NoContextError)
105
+ end
106
+ end
107
+
108
+ describe '#block' do
109
+ it 'changes client within block' do
110
+ outer = Fauna::Client.new
111
+ inner = Fauna::Client.new
112
+ Fauna::Context.push(outer)
113
+
114
+ expect(Fauna::Context.client).to be(outer)
115
+ Fauna::Context.block(inner) do
116
+ expect(Fauna::Context.client).to be(inner)
117
+ end
118
+ expect(Fauna::Context.client).to be(outer)
119
+ end
120
+ end
121
+ end