estore 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.simplecov +14 -0
- data/.travis.yml +1 -1
- data/CHANGELOG.md +28 -0
- data/Gemfile +1 -10
- data/README.md +12 -11
- data/estore.gemspec +2 -1
- data/lib/estore/commands.rb +5 -3
- data/lib/estore/commands/append.rb +9 -8
- data/lib/estore/commands/base.rb +18 -18
- data/lib/estore/commands/read.rb +28 -0
- data/lib/estore/commands/{read_batch.rb → reads/batch.rb} +11 -4
- data/lib/estore/commands/{read_forward.rb → reads/forward.rb} +15 -3
- data/lib/estore/commands/subscription.rb +1 -12
- data/lib/estore/commands/{catch_up_subscription.rb → subscriptions/catch_up.rb} +12 -13
- data/lib/estore/commands/subscriptions/live.rb +15 -0
- data/lib/estore/connection.rb +2 -2
- data/lib/estore/connection/buffer.rb +2 -2
- data/lib/estore/connection_context.rb +10 -2
- data/lib/estore/message_extensions.rb +5 -3
- data/lib/estore/package.rb +8 -0
- data/lib/estore/session.rb +2 -2
- data/lib/estore/version.rb +1 -1
- data/spec/integration/session_spec.rb +18 -3
- data/spec/spec_helper.rb +3 -5
- data/spec/unit/estore/commands/append_spec.rb +35 -0
- data/spec/unit/estore/commands/reads/batch_spec.rb +34 -0
- data/spec/unit/estore/commands/reads/forward_spec.rb +34 -0
- data/spec/unit/estore/connection_context_spec.rb +53 -0
- data/spec/unit/estore/connection_mock.rb +22 -0
- data/spec/unit/estore/package_spec.rb +9 -0
- metadata +35 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdd806cd7c12b665577e8f686f9a14225fd102ce
|
4
|
+
data.tar.gz: 519601368cfc6e8d30912510fadbd2b866eff7e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e554e45930e79aeb9c1eca4cdc5437bc8a26f3228c02b71d63c4c5e1c573cac7268e83d51bcd96bf619c7b430d1ca22eaaffbe224c44b139f6e4e031b1306dd
|
7
|
+
data.tar.gz: 1ef5c432b902a710b61886b4e0ba5eee9448c021978add9d93b033b9b747dd5a693e019c960b855ea005cc350f781b9bdea73351f85905b958c7d5e0a348a29b
|
data/.simplecov
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
SimpleCov.start do
|
2
|
+
project_name 'estore'
|
3
|
+
|
4
|
+
# Filter out the following files
|
5
|
+
add_filter '/spec/'
|
6
|
+
add_filter '/gems/'
|
7
|
+
add_filter '/config/'
|
8
|
+
|
9
|
+
require 'coveralls'
|
10
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
11
|
+
Coveralls::SimpleCov::Formatter,
|
12
|
+
SimpleCov::Formatter::HTMLFormatter
|
13
|
+
]
|
14
|
+
end
|
data/.travis.yml
CHANGED
@@ -5,7 +5,7 @@ bundler_args: --without yard guard benchmarks tools
|
|
5
5
|
env:
|
6
6
|
global:
|
7
7
|
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
8
|
-
- CODECLIMATE_REPO_TOKEN=
|
8
|
+
- CODECLIMATE_REPO_TOKEN=c571107e67aa90424c4d4256a3ad20127d1c64104b83d43f3ec23630c7aa19da
|
9
9
|
install:
|
10
10
|
- "wget -nc http://download.geteventstore.com/binaries/EventStore-OSS-Linux-v3.0.3.tar.gz"
|
11
11
|
- "tar -xvzf EventStore-OSS-Linux-v3.0.3.tar.gz"
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
## v0.1.2 - 2015-04-05
|
2
|
+
### Added
|
3
|
+
* Errors during commands reject promises too
|
4
|
+
* Unit testing started
|
5
|
+
|
6
|
+
[Compare v0.1.1...v0.1.2](https://github.com/rom-rb/rom-event_store/compare/v0.1.1...v0.1.2)
|
7
|
+
|
8
|
+
## v0.1.1 - 2015-04-05
|
9
|
+
### Added
|
10
|
+
* General errors during connection reject command promises
|
11
|
+
|
12
|
+
[Compare v0.1.0...v0.1.1](https://github.com/rom-rb/rom-event_store/compare/v0.1.0...v0.1.1)
|
13
|
+
|
14
|
+
## v0.1.0 - 2015-04-03
|
15
|
+
### Added
|
16
|
+
* General refactoring using the concept of `Command`
|
17
|
+
|
18
|
+
[Compare v0.0.2...v0.1.0](https://github.com/rom-rb/rom-event_store/compare/v0.0.2...v0.1.0)
|
19
|
+
|
20
|
+
## v0.0.2 - 2015-04-01
|
21
|
+
### Added
|
22
|
+
* Gem name changed to `estore`
|
23
|
+
* Minor refactoring
|
24
|
+
|
25
|
+
[Compare v0.0.1...v0.0.2](https://github.com/rom-rb/rom-event_store/compare/v0.0.1...v0.0.2)
|
26
|
+
|
27
|
+
## v0.0.1 - 2015-03-31
|
28
|
+
Forked from [eventstore-ruby](https://github.com/mathieuravaux/eventstore-ruby)
|
data/Gemfile
CHANGED
@@ -4,14 +4,5 @@ source 'https://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
group :test do
|
7
|
-
gem '
|
8
|
-
gem 'codeclimate-test-reporter', require: false
|
9
|
-
end
|
10
|
-
|
11
|
-
group :tools do
|
12
|
-
gem 'rubocop'
|
13
|
-
|
14
|
-
gem 'guard'
|
15
|
-
gem 'guard-rspec'
|
16
|
-
gem 'guard-rubocop'
|
7
|
+
gem 'coveralls', require: false
|
17
8
|
end
|
data/README.md
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
[gem]: https://rubygems.org/gems/estore
|
2
|
-
[travis]: https://travis-ci.org/
|
3
|
-
[gemnasium]: https://gemnasium.com/
|
4
|
-
[codeclimate]: https://codeclimate.com/github/
|
5
|
-
[
|
6
|
-
[
|
2
|
+
[travis]: https://travis-ci.org/eventstore-rb/estore
|
3
|
+
[gemnasium]: https://gemnasium.com/eventstore-rb/estore
|
4
|
+
[codeclimate]: https://codeclimate.com/github/eventstore-rb/estore
|
5
|
+
[coveralls]: https://coveralls.io/r/eventstore-rb/estore
|
6
|
+
[inchpages]: http://inch-ci.org/github/eventstore-rb/estore
|
7
|
+
[gitter]: https://gitter.im/eventstore-rb/estore?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
7
8
|
|
8
9
|
# Estore
|
9
10
|
|
10
11
|
[][gem]
|
11
|
-
[][travis]
|
13
|
+
[][gemnasium]
|
14
|
+
[][codeclimate]
|
15
|
+
[][coveralls]
|
16
|
+
[][inchpages]
|
17
|
+
[][gitter]
|
17
18
|
|
18
19
|
An [Event Store](http://geteventstore.com/) driver for Ruby
|
19
20
|
|
data/estore.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ['mathieu.ravaux@gmail.com', 'hector0193@gmail.com']
|
11
11
|
spec.summary = 'An Event Store driver for Ruby'
|
12
12
|
spec.description = 'TCP driver to read and write events to Event Store'
|
13
|
-
spec.homepage = 'https://github.com/
|
13
|
+
spec.homepage = 'https://github.com/eventstore-rb/estore'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency 'bundler'
|
25
25
|
spec.add_development_dependency 'rake', '~> 10.0'
|
26
26
|
spec.add_development_dependency 'rubocop', '~> 0.28.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
27
28
|
end
|
data/lib/estore/commands.rb
CHANGED
@@ -2,7 +2,9 @@ require 'estore/commands/promise'
|
|
2
2
|
require 'estore/commands/base'
|
3
3
|
require 'estore/commands/append'
|
4
4
|
require 'estore/commands/ping'
|
5
|
-
require 'estore/commands/
|
6
|
-
require 'estore/commands/
|
5
|
+
require 'estore/commands/read'
|
6
|
+
require 'estore/commands/reads/batch'
|
7
|
+
require 'estore/commands/reads/forward'
|
7
8
|
require 'estore/commands/subscription'
|
8
|
-
require 'estore/commands/
|
9
|
+
require 'estore/commands/subscriptions/live'
|
10
|
+
require 'estore/commands/subscriptions/catch_up'
|
@@ -3,9 +3,7 @@ module Estore
|
|
3
3
|
class Append
|
4
4
|
include Command
|
5
5
|
|
6
|
-
|
7
|
-
json: 1
|
8
|
-
}
|
6
|
+
handle WriteEventsCompleted => :completed
|
9
7
|
|
10
8
|
def initialize(connection, stream, events, options = {})
|
11
9
|
super(connection)
|
@@ -13,23 +11,22 @@ module Estore
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def call
|
14
|
+
register!
|
15
|
+
|
16
16
|
msg = WriteEvents.new(
|
17
17
|
event_stream_id: @stream,
|
18
18
|
expected_version: @options[:expected_version] || -2,
|
19
19
|
events: Array(@events).map { |event| new_event(event) },
|
20
20
|
require_master: true
|
21
21
|
)
|
22
|
-
|
23
|
-
register!
|
24
22
|
write('WriteEvents', msg)
|
23
|
+
|
25
24
|
promise
|
26
25
|
end
|
27
26
|
|
28
|
-
def
|
27
|
+
def completed(response)
|
29
28
|
remove!
|
30
29
|
|
31
|
-
response = decode(WriteEventsCompleted, message)
|
32
|
-
|
33
30
|
if response.result == OperationResult::Success
|
34
31
|
promise.fulfill(response)
|
35
32
|
else
|
@@ -39,6 +36,10 @@ module Estore
|
|
39
36
|
|
40
37
|
private
|
41
38
|
|
39
|
+
CONTENT_TYPES = {
|
40
|
+
json: 1
|
41
|
+
}
|
42
|
+
|
42
43
|
def new_event(event)
|
43
44
|
uuid = event[:id] || SecureRandom.uuid
|
44
45
|
content_type = event.fetch(:content_type, :json)
|
data/lib/estore/commands/base.rb
CHANGED
@@ -3,6 +3,12 @@ module Estore
|
|
3
3
|
module Command
|
4
4
|
attr_reader :uuid
|
5
5
|
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.singleton_class.class_eval { attr_accessor :handlers }
|
9
|
+
base.handlers = {}
|
10
|
+
end
|
11
|
+
|
6
12
|
def initialize(connection)
|
7
13
|
@connection = connection
|
8
14
|
@uuid = SecureRandom.uuid
|
@@ -28,26 +34,20 @@ module Estore
|
|
28
34
|
@promise ||= Promise.new(@uuid)
|
29
35
|
end
|
30
36
|
|
31
|
-
def
|
32
|
-
|
33
|
-
rescue => error
|
34
|
-
puts "Protobuf decoding error on connection #{object_id}"
|
35
|
-
puts type: type, message: message
|
36
|
-
puts error.backtrace
|
37
|
-
raise error
|
38
|
-
end
|
37
|
+
def handle(message)
|
38
|
+
handler = self.class.handlers[message.class]
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
require_master: false
|
48
|
-
)
|
40
|
+
if handler
|
41
|
+
send(handler, message) unless handler == :ignore
|
42
|
+
else
|
43
|
+
$stderr.puts "#{message.class} arrived but not handled by "\
|
44
|
+
"command #{self.class}"
|
45
|
+
end
|
46
|
+
end
|
49
47
|
|
50
|
-
|
48
|
+
module ClassMethods
|
49
|
+
def handle(hash)
|
50
|
+
handlers.update(hash)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Estore
|
2
|
+
module Commands
|
3
|
+
module ReadStreamForward
|
4
|
+
def read(stream, from, limit)
|
5
|
+
msg = ReadStreamEvents.new(
|
6
|
+
event_stream_id: stream,
|
7
|
+
from_event_number: from,
|
8
|
+
max_count: limit,
|
9
|
+
resolve_link_tos: true,
|
10
|
+
require_master: false
|
11
|
+
)
|
12
|
+
|
13
|
+
write('ReadStreamEventsForward', msg)
|
14
|
+
end
|
15
|
+
|
16
|
+
def error(response)
|
17
|
+
case response.result
|
18
|
+
when ReadStreamEventsCompleted::ReadStreamResult::AccessDenied
|
19
|
+
:access_denied
|
20
|
+
when ReadStreamEventsCompleted::ReadStreamResult::Error
|
21
|
+
response.error ? response.error : 'No message given'
|
22
|
+
else
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -2,7 +2,9 @@ module Estore
|
|
2
2
|
module Commands
|
3
3
|
class ReadBatch
|
4
4
|
include Command
|
5
|
-
include
|
5
|
+
include ReadStreamForward
|
6
|
+
|
7
|
+
handle ReadStreamEventsForwardCompleted => :completed
|
6
8
|
|
7
9
|
def initialize(connection, stream, from, limit)
|
8
10
|
super(connection)
|
@@ -15,10 +17,15 @@ module Estore
|
|
15
17
|
promise
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
20
|
+
def completed(response)
|
19
21
|
remove!
|
20
|
-
|
21
|
-
|
22
|
+
error = error(response)
|
23
|
+
|
24
|
+
if error
|
25
|
+
promise.reject error
|
26
|
+
else
|
27
|
+
promise.fulfill(Array(response.events))
|
28
|
+
end
|
22
29
|
end
|
23
30
|
end
|
24
31
|
end
|
@@ -2,7 +2,9 @@ module Estore
|
|
2
2
|
module Commands
|
3
3
|
class ReadForward
|
4
4
|
include Command
|
5
|
-
include
|
5
|
+
include ReadStreamForward
|
6
|
+
|
7
|
+
handle ReadStreamEventsCompleted => :batch_completed
|
6
8
|
|
7
9
|
def initialize(connection, stream, from, batch_size = nil, &block)
|
8
10
|
super(connection)
|
@@ -20,8 +22,7 @@ module Estore
|
|
20
22
|
promise
|
21
23
|
end
|
22
24
|
|
23
|
-
def
|
24
|
-
response = decode(ReadStreamEventsCompleted, message)
|
25
|
+
def keep_reading(response)
|
25
26
|
events = Array(response.events)
|
26
27
|
|
27
28
|
@from += events.size
|
@@ -34,6 +35,17 @@ module Estore
|
|
34
35
|
promise.fulfill(@block ? nil : @events)
|
35
36
|
end
|
36
37
|
end
|
38
|
+
|
39
|
+
def batch_completed(response)
|
40
|
+
error = error(response)
|
41
|
+
|
42
|
+
if error
|
43
|
+
remove!
|
44
|
+
promise.reject error
|
45
|
+
else
|
46
|
+
keep_reading(response)
|
47
|
+
end
|
48
|
+
end
|
37
49
|
end
|
38
50
|
end
|
39
51
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Estore
|
2
2
|
module Commands
|
3
|
-
|
4
|
-
include Command
|
5
|
-
|
3
|
+
module Subscription
|
6
4
|
def initialize(connection, stream, options = {})
|
7
5
|
super(connection)
|
8
6
|
@has_finished = false
|
@@ -10,10 +8,6 @@ module Estore
|
|
10
8
|
@resolve_link_tos = options.fetch(:resolve_link_tos, true)
|
11
9
|
end
|
12
10
|
|
13
|
-
def finished?
|
14
|
-
@has_finished
|
15
|
-
end
|
16
|
-
|
17
11
|
def call
|
18
12
|
start
|
19
13
|
end
|
@@ -39,11 +33,6 @@ module Estore
|
|
39
33
|
@handler = block
|
40
34
|
end
|
41
35
|
|
42
|
-
def handle(message, type)
|
43
|
-
dispatch(decode(StreamEventAppeared, message).event) if
|
44
|
-
type == 'StreamEventAppeared'
|
45
|
-
end
|
46
|
-
|
47
36
|
def dispatch(event)
|
48
37
|
@position = event.original_event_number
|
49
38
|
@handler.call(event)
|
@@ -1,11 +1,14 @@
|
|
1
1
|
module Estore
|
2
2
|
module Commands
|
3
|
-
class CatchUpSubscription
|
3
|
+
class CatchUpSubscription
|
4
4
|
include Command
|
5
|
+
include Subscription
|
6
|
+
|
7
|
+
handle StreamEventAppeared => :event_appeared,
|
8
|
+
SubscriptionConfirmation => :ignore
|
5
9
|
|
6
10
|
def initialize(connection, stream, from, options = {})
|
7
|
-
super(connection, options)
|
8
|
-
@stream = stream
|
11
|
+
super(connection, stream, options)
|
9
12
|
@from = from
|
10
13
|
@batch = options[:batch_size]
|
11
14
|
@mutex = Mutex.new
|
@@ -42,18 +45,14 @@ module Estore
|
|
42
45
|
@queue.find_all { |event| event.original_event_number > @position }
|
43
46
|
end
|
44
47
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
unless @caught_up
|
50
|
-
@mutex.synchronize do
|
51
|
-
@queue << event unless @caught_up
|
52
|
-
end
|
48
|
+
def event_appeared(response)
|
49
|
+
unless @caught_up
|
50
|
+
@mutex.synchronize do
|
51
|
+
@queue << response.event unless @caught_up
|
53
52
|
end
|
54
|
-
|
55
|
-
dispatch(event) if @caught_up
|
56
53
|
end
|
54
|
+
|
55
|
+
dispatch(response.event) if @caught_up
|
57
56
|
end
|
58
57
|
end
|
59
58
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Estore
|
2
|
+
module Commands
|
3
|
+
class LiveSubscription
|
4
|
+
include Command
|
5
|
+
include Commands::Subscription
|
6
|
+
|
7
|
+
handle StreamEventAppeared => :event_appeared,
|
8
|
+
SubscriptionConfirmation => :ignore
|
9
|
+
|
10
|
+
def event_appeared(response)
|
11
|
+
dispatch(response.event)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/estore/connection.rb
CHANGED
@@ -34,11 +34,11 @@ module Estore
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
def on_received_package(
|
37
|
+
def on_received_package(type, package, uuid, _flags)
|
38
38
|
if type == 'HeartbeatRequestCommand'
|
39
39
|
write(SecureRandom.uuid, 'HeartbeatResponseCommand')
|
40
40
|
else
|
41
|
-
@context.dispatch(uuid,
|
41
|
+
@context.dispatch(uuid, Package.decode(type, package))
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -42,9 +42,9 @@ module Estore
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def handle(pkg)
|
45
|
-
code, flags, uuid_bytes,
|
45
|
+
code, flags, uuid_bytes, package = parse(pkg)
|
46
46
|
command = Estore::Connection.command_name(code)
|
47
|
-
@handler.call(
|
47
|
+
@handler.call(command, package, Package.parse_uuid(uuid_bytes), flags)
|
48
48
|
end
|
49
49
|
|
50
50
|
def parse(pkg)
|
@@ -20,15 +20,23 @@ module Estore
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
def dispatch(uuid, message
|
23
|
+
def dispatch(uuid, message)
|
24
24
|
command = @commands[uuid]
|
25
|
-
command.handle(message
|
25
|
+
command.handle(message) if command
|
26
|
+
rescue => error
|
27
|
+
command.reject! error
|
28
|
+
remove(command)
|
29
|
+
end
|
30
|
+
|
31
|
+
def empty?
|
32
|
+
@commands.empty?
|
26
33
|
end
|
27
34
|
|
28
35
|
def on_error(error)
|
29
36
|
# TODO: Error handling
|
30
37
|
@mutex.synchronize do
|
31
38
|
@commands.each { |_uuid, command| command.reject! error }
|
39
|
+
@commands = {}
|
32
40
|
end
|
33
41
|
end
|
34
42
|
end
|
@@ -13,7 +13,9 @@ module Estore
|
|
13
13
|
original_event.event_number
|
14
14
|
end
|
15
15
|
end
|
16
|
-
end
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
ResolvedEvent.send(:include, OriginalEventMixin)
|
18
|
+
ResolvedIndexedEvent.send(:include, OriginalEventMixin)
|
19
|
+
|
20
|
+
ReadStreamEventsForwardCompleted = ReadStreamEventsCompleted
|
21
|
+
end
|
data/lib/estore/package.rb
CHANGED
@@ -23,6 +23,14 @@ module Estore
|
|
23
23
|
uuid.scan(/[0-9a-f]{4}/).map { |x| x.to_i(16) }.pack('n*')
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.decode(type, message)
|
27
|
+
message.empty? ? nil : Estore.const_get(type).decode(message)
|
28
|
+
rescue => error
|
29
|
+
puts 'Decoding error:'
|
30
|
+
puts type: type, message: message
|
31
|
+
raise error
|
32
|
+
end
|
33
|
+
|
26
34
|
def self.parse_uuid(bytes)
|
27
35
|
a, b, c, d, e, f, g, h =
|
28
36
|
*bytes.unpack('n*').map { |n| n.to_s(16) }.map { |n| n.rjust(4, '0') }
|
data/lib/estore/session.rb
CHANGED
@@ -26,7 +26,7 @@ module Estore
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def ping
|
29
|
-
command(Commands::Ping)
|
29
|
+
command(Commands::Ping).call
|
30
30
|
end
|
31
31
|
|
32
32
|
def read(stream, options = {})
|
@@ -56,7 +56,7 @@ module Estore
|
|
56
56
|
if options[:from]
|
57
57
|
command(Commands::CatchUpSubscription, stream, options[:from], options)
|
58
58
|
else
|
59
|
-
command(Commands::
|
59
|
+
command(Commands::LiveSubscription, stream, options)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
data/lib/estore/version.rb
CHANGED
@@ -39,6 +39,10 @@ describe Estore::Session do
|
|
39
39
|
stream
|
40
40
|
end
|
41
41
|
|
42
|
+
it 'pings the Event Store' do
|
43
|
+
Timeout.timeout(5) { session.ping.sync }
|
44
|
+
end
|
45
|
+
|
42
46
|
it 'reads all the events from a stream' do
|
43
47
|
stream = session.read(stream_with(200)).sync
|
44
48
|
|
@@ -57,6 +61,12 @@ describe Estore::Session do
|
|
57
61
|
expect(stream).to have(15).events.starting_at(10)
|
58
62
|
end
|
59
63
|
|
64
|
+
it 'reads no events if the stream does not exist' do
|
65
|
+
stream = session.read('doesnotexist').sync
|
66
|
+
|
67
|
+
expect(stream).to have(0).events
|
68
|
+
end
|
69
|
+
|
60
70
|
it 'allows to make a live subscription' do
|
61
71
|
stream = random_stream
|
62
72
|
received = []
|
@@ -79,18 +89,23 @@ describe Estore::Session do
|
|
79
89
|
stream_with(2100, stream)
|
80
90
|
|
81
91
|
sub = session.subscription(stream, from: 30)
|
92
|
+
|
82
93
|
sub.on_event do |event|
|
94
|
+
# Events received during processing should be
|
95
|
+
# received later too
|
96
|
+
sleep 1 if received.size < 1
|
83
97
|
received << event
|
84
98
|
puts "Receiving... #{received.size}"
|
85
99
|
end
|
86
|
-
sub.start
|
87
100
|
|
88
101
|
Thread.new do
|
89
|
-
|
102
|
+
30.times do
|
90
103
|
stream_with(2, stream)
|
91
104
|
end
|
92
105
|
end
|
93
106
|
|
94
|
-
|
107
|
+
sub.start
|
108
|
+
|
109
|
+
expect(received).to have(2130).events.starting_at(30).before(20.seconds)
|
95
110
|
end
|
96
111
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'codeclimate-test-reporter'
|
4
|
-
CodeClimate::TestReporter.start
|
5
|
-
end
|
6
|
-
|
2
|
+
require 'simplecov'
|
7
3
|
require 'estore'
|
8
4
|
|
9
5
|
trap 'TTIN' do
|
@@ -39,6 +35,8 @@ RSpec::Matchers.define :have do |expectation|
|
|
39
35
|
expect(wrapper.event.event_number).to be(index + @start)
|
40
36
|
end
|
41
37
|
end
|
38
|
+
|
39
|
+
true
|
42
40
|
end
|
43
41
|
|
44
42
|
chain(:events) {}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'unit/estore/connection_mock'
|
3
|
+
|
4
|
+
describe Estore::Commands::Append do
|
5
|
+
subject(:append) do
|
6
|
+
Estore::Commands::Append.new(connection, 'test-stream', events)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:events) do
|
10
|
+
[{ type: 'something', data: 'something else' }, { type: 'stuff' }]
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:connection) { Estore::ConnectionMock.new }
|
14
|
+
let(:promise) { append.call }
|
15
|
+
|
16
|
+
before do
|
17
|
+
promise
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'writes a message with the events to the connection buffer' do
|
21
|
+
_uuid, _type, msg = connection.buffer.first
|
22
|
+
|
23
|
+
expect(msg.events.size).to be(events.size)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'rejects the promise on errors' do
|
27
|
+
append.handle(
|
28
|
+
Estore::WriteEventsCompleted.new(
|
29
|
+
result: Estore::OperationResult::AccessDenied
|
30
|
+
)
|
31
|
+
)
|
32
|
+
|
33
|
+
expect { promise.sync }.to raise_exception
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'unit/estore/connection_mock'
|
3
|
+
|
4
|
+
describe Estore::Commands::ReadBatch do
|
5
|
+
subject(:read) do
|
6
|
+
Estore::Commands::ReadBatch.new(connection, 'test-stream', 5, 10)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:message) { Estore::ReadStreamEventsCompleted }
|
10
|
+
let(:connection) { Estore::ConnectionMock.new }
|
11
|
+
let(:promise) { read.call }
|
12
|
+
|
13
|
+
def result(type)
|
14
|
+
message.new(
|
15
|
+
result: message::ReadStreamResult.const_get(type)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
promise
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'rejects the promise on errors' do
|
24
|
+
read.handle(result(:Error))
|
25
|
+
|
26
|
+
expect { promise.sync }.to raise_exception
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'rejects the promise when access is denied' do
|
30
|
+
read.handle(result(:AccessDenied))
|
31
|
+
|
32
|
+
expect { promise.sync }.to raise_exception
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'unit/estore/connection_mock'
|
3
|
+
|
4
|
+
describe Estore::Commands::ReadForward do
|
5
|
+
subject(:read) do
|
6
|
+
Estore::Commands::ReadForward.new(connection, 'test-stream', 5, 10)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:message) { Estore::ReadStreamEventsCompleted }
|
10
|
+
let(:connection) { Estore::ConnectionMock.new }
|
11
|
+
let(:promise) { read.call }
|
12
|
+
|
13
|
+
def result(type)
|
14
|
+
message.new(
|
15
|
+
result: message::ReadStreamResult.const_get(type)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
promise
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'rejects the promise on errors' do
|
24
|
+
read.handle(result(:Error))
|
25
|
+
|
26
|
+
expect { promise.sync }.to raise_exception
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'rejects the promise when access is denied' do
|
30
|
+
read.handle(result(:AccessDenied))
|
31
|
+
|
32
|
+
expect { promise.sync }.to raise_exception
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Estore::ConnectionContext do
|
4
|
+
subject(:context) { Estore::ConnectionContext.new }
|
5
|
+
|
6
|
+
let(:bad_command) do
|
7
|
+
BadCommand = Class.new do
|
8
|
+
attr_reader :error
|
9
|
+
|
10
|
+
def uuid
|
11
|
+
'test'
|
12
|
+
end
|
13
|
+
|
14
|
+
def reject!(error)
|
15
|
+
@error = error
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle(_msg)
|
19
|
+
boom
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
BadCommand.new
|
24
|
+
end
|
25
|
+
|
26
|
+
before do
|
27
|
+
context.register(bad_command)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'rejects a command when exceptions happen inside the command' do
|
31
|
+
context.dispatch('test', 'something')
|
32
|
+
|
33
|
+
expect(bad_command.error).to be_instance_of(NameError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'removes all commands when exceptions happen inside the command' do
|
37
|
+
context.dispatch('test', 'something')
|
38
|
+
|
39
|
+
expect(context.empty?).to be_truthy
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'rejects a command when exceptions happen in the connection' do
|
43
|
+
context.on_error(StandardError.new('this is an error'))
|
44
|
+
|
45
|
+
expect(bad_command.error).to be_instance_of(StandardError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'removes all commands when exceptions happen in the connection' do
|
49
|
+
context.on_error('this is an error')
|
50
|
+
|
51
|
+
expect(context.empty?).to be_truthy
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Estore
|
2
|
+
class ConnectionMock
|
3
|
+
attr_reader :buffer, :registry
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@buffer = []
|
7
|
+
@registry = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(uuid, type, msg)
|
11
|
+
@buffer << [uuid, type, msg]
|
12
|
+
end
|
13
|
+
|
14
|
+
def register(command)
|
15
|
+
@registry[command.uuid] = command
|
16
|
+
end
|
17
|
+
|
18
|
+
def remove(command)
|
19
|
+
@registry.delete(command.uuid)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: estore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mathieu Ravaux
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-04-
|
12
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: beefcake
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 0.28.0
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.1'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '3.1'
|
84
98
|
description: TCP driver to read and write events to Event Store
|
85
99
|
email:
|
86
100
|
- mathieu.ravaux@gmail.com
|
@@ -91,6 +105,7 @@ extra_rdoc_files: []
|
|
91
105
|
files:
|
92
106
|
- ".gitignore"
|
93
107
|
- ".rubocop.yml"
|
108
|
+
- ".simplecov"
|
94
109
|
- ".travis.yml"
|
95
110
|
- ".yardopts"
|
96
111
|
- CHANGELOG.md
|
@@ -103,12 +118,14 @@ files:
|
|
103
118
|
- lib/estore/commands.rb
|
104
119
|
- lib/estore/commands/append.rb
|
105
120
|
- lib/estore/commands/base.rb
|
106
|
-
- lib/estore/commands/catch_up_subscription.rb
|
107
121
|
- lib/estore/commands/ping.rb
|
108
122
|
- lib/estore/commands/promise.rb
|
109
|
-
- lib/estore/commands/
|
110
|
-
- lib/estore/commands/
|
123
|
+
- lib/estore/commands/read.rb
|
124
|
+
- lib/estore/commands/reads/batch.rb
|
125
|
+
- lib/estore/commands/reads/forward.rb
|
111
126
|
- lib/estore/commands/subscription.rb
|
127
|
+
- lib/estore/commands/subscriptions/catch_up.rb
|
128
|
+
- lib/estore/commands/subscriptions/live.rb
|
112
129
|
- lib/estore/connection.rb
|
113
130
|
- lib/estore/connection/buffer.rb
|
114
131
|
- lib/estore/connection/protocol.rb
|
@@ -121,8 +138,14 @@ files:
|
|
121
138
|
- lib/estore/version.rb
|
122
139
|
- spec/integration/session_spec.rb
|
123
140
|
- spec/spec_helper.rb
|
141
|
+
- spec/unit/estore/commands/append_spec.rb
|
142
|
+
- spec/unit/estore/commands/reads/batch_spec.rb
|
143
|
+
- spec/unit/estore/commands/reads/forward_spec.rb
|
144
|
+
- spec/unit/estore/connection_context_spec.rb
|
145
|
+
- spec/unit/estore/connection_mock.rb
|
146
|
+
- spec/unit/estore/package_spec.rb
|
124
147
|
- vendor/proto/ClientMessageDtos.proto
|
125
|
-
homepage: https://github.com/
|
148
|
+
homepage: https://github.com/eventstore-rb/estore
|
126
149
|
licenses:
|
127
150
|
- MIT
|
128
151
|
metadata: {}
|
@@ -149,3 +172,9 @@ summary: An Event Store driver for Ruby
|
|
149
172
|
test_files:
|
150
173
|
- spec/integration/session_spec.rb
|
151
174
|
- spec/spec_helper.rb
|
175
|
+
- spec/unit/estore/commands/append_spec.rb
|
176
|
+
- spec/unit/estore/commands/reads/batch_spec.rb
|
177
|
+
- spec/unit/estore/commands/reads/forward_spec.rb
|
178
|
+
- spec/unit/estore/connection_context_spec.rb
|
179
|
+
- spec/unit/estore/connection_mock.rb
|
180
|
+
- spec/unit/estore/package_spec.rb
|