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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78dbb09be7de8d003f5e6c5241a96df71b47c2db
4
- data.tar.gz: 2e5cc0c9440c44154542855e92c014fe11fa7e83
3
+ metadata.gz: bdd806cd7c12b665577e8f686f9a14225fd102ce
4
+ data.tar.gz: 519601368cfc6e8d30912510fadbd2b866eff7e8
5
5
  SHA512:
6
- metadata.gz: 852983cf3c549846b0638e2405531b4455e8fc8ef4961b0f65f3de1a4f4dd3e676446b3c7acd5b6aeb320ad91fe9cf5b2dc10c1931cb96244f27ee204c6113e3
7
- data.tar.gz: 75bea923d74418ea433f5e03952cf76ba302daa82ec7d8704dde450154c86807049562f60038905f1e0c1de7d34d9abb54b183cd86f4c9b7f7097ebb17c5bcdc
6
+ metadata.gz: 5e554e45930e79aeb9c1eca4cdc5437bc8a26f3228c02b71d63c4c5e1c573cac7268e83d51bcd96bf619c7b430d1ca22eaaffbe224c44b139f6e4e031b1306dd
7
+ data.tar.gz: 1ef5c432b902a710b61886b4e0ba5eee9448c021978add9d93b033b9b747dd5a693e019c960b855ea005cc350f781b9bdea73351f85905b958c7d5e0a348a29b
@@ -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
@@ -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=86bb9d558da8217d85126a02c4a264dc8789bb4cc8d3949e8fcbabca0440f2fa
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"
@@ -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 'rspec', '~> 3.1'
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/rom-eventstore/estore
3
- [gemnasium]: https://gemnasium.com/rom-eventstore/estore
4
- [codeclimate]: https://codeclimate.com/github/rom-eventstore/estore
5
- [inchpages]: http://inch-ci.org/github/rom-eventstore/estore
6
- [gitter]: https://gitter.im/rom-eventstore/estore?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
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 Version](https://badge.fury.io/rb/estore.svg)][gem]
11
- [![Build Status](https://travis-ci.org/rom-eventstore/estore.svg?branch=master)][travis]
12
- [![Dependency Status](https://gemnasium.com/rom-eventstore/estore.png)][gemnasium]
13
- [![Code Climate](https://codeclimate.com/github/rom-eventstore/estore/badges/gpa.svg)][codeclimate]
14
- [![Test Coverage](https://codeclimate.com/github/rom-eventstore/estore/badges/coverage.svg)][codeclimate]
15
- [![Inline docs](http://inch-ci.org/github/rom-eventstore/estore.svg?branch=master)][inchpages]
16
- [![Join the chat at https://gitter.im/rom-eventstore/estore](https://badges.gitter.im/Join%20Chat.svg)][gitter]
12
+ [![Build Status](https://travis-ci.org/eventstore-rb/estore.svg?branch=master)][travis]
13
+ [![Dependency Status](https://gemnasium.com/eventstore-rb/estore.png)][gemnasium]
14
+ [![Code Climate](https://codeclimate.com/github/eventstore-rb/estore/badges/gpa.svg)][codeclimate]
15
+ [![Coverage Status](https://coveralls.io/repos/eventstore-rb/estore/badge.svg)][coveralls]
16
+ [![Inline docs](http://inch-ci.org/github/eventstore-rb/estore.svg?branch=master)][inchpages]
17
+ [![Join the chat at https://gitter.im/eventstore-rb/estore](https://badges.gitter.im/Join%20Chat.svg)][gitter]
17
18
 
18
19
  An [Event Store](http://geteventstore.com/) driver for Ruby
19
20
 
@@ -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/rom-eventstore/estore'
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
@@ -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/read_batch'
6
- require 'estore/commands/read_forward'
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/catch_up_subscription'
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
- CONTENT_TYPES = {
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 handle(message, *)
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)
@@ -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 decode(type, message)
32
- type.decode(message)
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
- module ReadStreamForward
41
- def read(stream, from, limit)
42
- msg = ReadStreamEvents.new(
43
- event_stream_id: stream,
44
- from_event_number: from,
45
- max_count: limit,
46
- resolve_link_tos: true,
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
- write('ReadStreamEventsForward', msg)
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 Command::ReadStreamForward
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 handle(message, *)
20
+ def completed(response)
19
21
  remove!
20
- response = decode(ReadStreamEventsCompleted, message)
21
- promise.fulfill(Array(response.events))
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 Command::ReadStreamForward
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 handle(message, *)
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
- class Subscription
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 < Subscription
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 handle(message, type)
46
- if type == 'StreamEventAppeared'
47
- event = decode(StreamEventAppeared, message).event
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
@@ -34,11 +34,11 @@ module Estore
34
34
 
35
35
  private
36
36
 
37
- def on_received_package(message, type, uuid, _flags)
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, message, type)
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, message = parse(pkg)
45
+ code, flags, uuid_bytes, package = parse(pkg)
46
46
  command = Estore::Connection.command_name(code)
47
- @handler.call(message, command, Package.parse_uuid(uuid_bytes), flags)
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, type)
23
+ def dispatch(uuid, message)
24
24
  command = @commands[uuid]
25
- command.handle(message, type) if command
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
- Estore::ResolvedEvent.send(:include, Estore::OriginalEventMixin)
19
- Estore::ResolvedIndexedEvent.send(:include, Estore::OriginalEventMixin)
17
+ ResolvedEvent.send(:include, OriginalEventMixin)
18
+ ResolvedIndexedEvent.send(:include, OriginalEventMixin)
19
+
20
+ ReadStreamEventsForwardCompleted = ReadStreamEventsCompleted
21
+ end
@@ -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') }
@@ -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::Subscription, stream, options)
59
+ command(Commands::LiveSubscription, stream, options)
60
60
  end
61
61
  end
62
62
 
@@ -1,3 +1,3 @@
1
1
  module Estore
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -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
- 50.times do
102
+ 30.times do
90
103
  stream_with(2, stream)
91
104
  end
92
105
  end
93
106
 
94
- expect(received).to have(2170).events.starting_at(30).before(20.seconds)
107
+ sub.start
108
+
109
+ expect(received).to have(2130).events.starting_at(30).before(20.seconds)
95
110
  end
96
111
  end
@@ -1,9 +1,5 @@
1
1
  # encoding: utf-8
2
- if RUBY_ENGINE == 'rbx'
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
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Estore::Package do
4
+ subject(:package) { Estore::Package }
5
+
6
+ it 'rejects the promise on errors' do
7
+ expect { package.decode('boom', 'boom') }.to raise_exception
8
+ end
9
+ 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.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-05 00:00:00.000000000 Z
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/read_batch.rb
110
- - lib/estore/commands/read_forward.rb
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/rom-eventstore/estore
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