estore 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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