aggro 0.0.1 → 0.0.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.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/.travis.yml +15 -0
  4. data/Gemfile +9 -0
  5. data/README.md +5 -1
  6. data/Rakefile +10 -0
  7. data/aggro.gemspec +8 -1
  8. data/lib/aggro.rb +191 -7
  9. data/lib/aggro/abstract_store.rb +12 -0
  10. data/lib/aggro/aggregate.rb +98 -0
  11. data/lib/aggro/aggregate_ref.rb +68 -6
  12. data/lib/aggro/attribute_dsl.rb +96 -0
  13. data/lib/aggro/binding_dsl.rb +45 -0
  14. data/lib/aggro/block_helper.rb +14 -0
  15. data/lib/aggro/channel.rb +37 -0
  16. data/lib/aggro/client.rb +12 -0
  17. data/lib/aggro/cluster_config.rb +57 -0
  18. data/lib/aggro/command.rb +16 -0
  19. data/lib/aggro/concurrent_actor.rb +26 -0
  20. data/lib/aggro/event_bus.rb +94 -0
  21. data/lib/aggro/event_dsl.rb +53 -0
  22. data/lib/aggro/event_proxy.rb +23 -0
  23. data/lib/aggro/event_serializer.rb +14 -0
  24. data/lib/aggro/file_store.rb +97 -0
  25. data/lib/aggro/file_store/reader.rb +21 -0
  26. data/lib/aggro/file_store/writer.rb +27 -0
  27. data/lib/aggro/handler/command.rb +60 -0
  28. data/lib/aggro/handler/create_aggregate.rb +42 -0
  29. data/lib/aggro/handler/get_events.rb +30 -0
  30. data/lib/aggro/handler/query.rb +60 -0
  31. data/lib/aggro/handler/start_saga.rb +56 -0
  32. data/lib/aggro/local_node.rb +28 -0
  33. data/lib/aggro/locator.rb +32 -0
  34. data/lib/aggro/message/ask.rb +16 -0
  35. data/lib/aggro/message/command.rb +36 -0
  36. data/lib/aggro/message/create_aggregate.rb +16 -0
  37. data/lib/aggro/message/endpoint.rb +16 -0
  38. data/lib/aggro/message/events.rb +24 -0
  39. data/lib/aggro/message/get_events.rb +16 -0
  40. data/lib/aggro/message/heartbeat.rb +16 -0
  41. data/lib/aggro/message/invalid_target.rb +20 -0
  42. data/lib/aggro/message/ok.rb +20 -0
  43. data/lib/aggro/message/publisher_endpoint_inquiry.rb +16 -0
  44. data/lib/aggro/message/query.rb +36 -0
  45. data/lib/aggro/message/result.rb +16 -0
  46. data/lib/aggro/message/start_saga.rb +28 -0
  47. data/lib/aggro/message/unhandled_operation.rb +20 -0
  48. data/lib/aggro/message/unknown_operation.rb +20 -0
  49. data/lib/aggro/message_parser.rb +10 -0
  50. data/lib/aggro/message_router.rb +26 -0
  51. data/lib/aggro/nanomsg_transport.rb +31 -0
  52. data/lib/aggro/nanomsg_transport/client.rb +35 -0
  53. data/lib/aggro/nanomsg_transport/connection.rb +98 -0
  54. data/lib/aggro/nanomsg_transport/publish.rb +17 -0
  55. data/lib/aggro/nanomsg_transport/publisher.rb +37 -0
  56. data/lib/aggro/nanomsg_transport/raw_reply.rb +18 -0
  57. data/lib/aggro/nanomsg_transport/raw_request.rb +18 -0
  58. data/lib/aggro/nanomsg_transport/reply.rb +17 -0
  59. data/lib/aggro/nanomsg_transport/request.rb +17 -0
  60. data/lib/aggro/nanomsg_transport/server.rb +84 -0
  61. data/lib/aggro/nanomsg_transport/socket_error.rb +20 -0
  62. data/lib/aggro/nanomsg_transport/subscribe.rb +27 -0
  63. data/lib/aggro/nanomsg_transport/subscriber.rb +82 -0
  64. data/lib/aggro/node.rb +29 -0
  65. data/lib/aggro/node_list.rb +39 -0
  66. data/lib/aggro/projection.rb +13 -0
  67. data/lib/aggro/query.rb +11 -0
  68. data/lib/aggro/saga.rb +94 -0
  69. data/lib/aggro/saga_runner.rb +87 -0
  70. data/lib/aggro/saga_runner/start_saga.rb +12 -0
  71. data/lib/aggro/saga_status.rb +29 -0
  72. data/lib/aggro/server.rb +88 -0
  73. data/lib/aggro/subscriber.rb +48 -0
  74. data/lib/aggro/subscription.rb +41 -0
  75. data/lib/aggro/transform/boolean.rb +16 -0
  76. data/lib/aggro/transform/email.rb +26 -0
  77. data/lib/aggro/transform/id.rb +34 -0
  78. data/lib/aggro/transform/integer.rb +22 -0
  79. data/lib/aggro/transform/money.rb +22 -0
  80. data/lib/aggro/transform/noop.rb +16 -0
  81. data/lib/aggro/transform/string.rb +16 -0
  82. data/lib/aggro/transform/time_interval.rb +24 -0
  83. data/lib/aggro/version.rb +1 -1
  84. data/spec/lib/aggro/abstract_store_spec.rb +15 -0
  85. data/spec/lib/aggro/aggregate_ref_spec.rb +63 -12
  86. data/spec/lib/aggro/aggregate_spec.rb +207 -0
  87. data/spec/lib/aggro/channel_spec.rb +87 -0
  88. data/spec/lib/aggro/client_spec.rb +26 -0
  89. data/spec/lib/aggro/cluster_config_spec.rb +33 -0
  90. data/spec/lib/aggro/command_spec.rb +52 -0
  91. data/spec/lib/aggro/concurrent_actor_spec.rb +44 -0
  92. data/spec/lib/aggro/event_bus_spec.rb +20 -0
  93. data/spec/lib/aggro/event_serializer_spec.rb +28 -0
  94. data/spec/lib/aggro/file_store/reader_spec.rb +32 -0
  95. data/spec/lib/aggro/file_store/writer_spec.rb +67 -0
  96. data/spec/lib/aggro/file_store_spec.rb +51 -0
  97. data/spec/lib/aggro/handler/command_spec.rb +78 -0
  98. data/spec/lib/aggro/handler/create_aggregate_spec.rb +64 -0
  99. data/spec/lib/aggro/handler/get_events_handler_spec.rb +45 -0
  100. data/spec/lib/aggro/handler/query_spec.rb +78 -0
  101. data/spec/lib/aggro/handler/start_saga_spec.rb +64 -0
  102. data/spec/lib/aggro/local_node_spec.rb +52 -0
  103. data/spec/lib/aggro/locator_spec.rb +61 -0
  104. data/spec/lib/aggro/message/ask_spec.rb +23 -0
  105. data/spec/lib/aggro/message/command_spec.rb +50 -0
  106. data/spec/lib/aggro/message/create_aggregate_spec.rb +28 -0
  107. data/spec/lib/aggro/message/endpoint_spec.rb +23 -0
  108. data/spec/lib/aggro/message/events_spec.rb +37 -0
  109. data/spec/lib/aggro/message/get_events_spec.rb +33 -0
  110. data/spec/lib/aggro/message/heartbeat_spec.rb +23 -0
  111. data/spec/lib/aggro/message/invalid_target_spec.rb +28 -0
  112. data/spec/lib/aggro/message/ok_spec.rb +27 -0
  113. data/spec/lib/aggro/message/publisher_endpoint_inquiry_spec.rb +23 -0
  114. data/spec/lib/aggro/message/query_spec.rb +50 -0
  115. data/spec/lib/aggro/message/start_saga_spec.rb +37 -0
  116. data/spec/lib/aggro/message/unhandled_operation_spec.rb +28 -0
  117. data/spec/lib/aggro/message/unknown_operation_spec.rb +28 -0
  118. data/spec/lib/aggro/message_parser_spec.rb +16 -0
  119. data/spec/lib/aggro/message_router_spec.rb +35 -0
  120. data/spec/lib/aggro/nanomsg_transport/socket_error_spec.rb +21 -0
  121. data/spec/lib/aggro/nanomsg_transport_spec.rb +37 -0
  122. data/spec/lib/aggro/node_list_spec.rb +38 -0
  123. data/spec/lib/aggro/node_spec.rb +44 -0
  124. data/spec/lib/aggro/projection_spec.rb +22 -0
  125. data/spec/lib/aggro/query_spec.rb +47 -0
  126. data/spec/lib/aggro/saga_runner_spec.rb +84 -0
  127. data/spec/lib/aggro/saga_spec.rb +126 -0
  128. data/spec/lib/aggro/saga_status_spec.rb +56 -0
  129. data/spec/lib/aggro/server_spec.rb +118 -0
  130. data/spec/lib/aggro/subscriber_spec.rb +59 -0
  131. data/spec/lib/aggro/subscription_spec.rb +50 -0
  132. data/spec/lib/aggro/transform/boolean_spec.rb +23 -0
  133. data/spec/lib/aggro/transform/email_spec.rb +13 -0
  134. data/spec/lib/aggro/transform/id_spec.rb +70 -0
  135. data/spec/lib/aggro/transform/integer_spec.rb +30 -0
  136. data/spec/lib/aggro/transform/money_spec.rb +34 -0
  137. data/spec/lib/aggro/transform/string_spec.rb +15 -0
  138. data/spec/lib/aggro/transform/time_interval_spec.rb +29 -0
  139. data/spec/lib/aggro_spec.rb +63 -19
  140. data/spec/spec_helper.rb +21 -2
  141. metadata +283 -3
@@ -0,0 +1,23 @@
1
+ RSpec.describe Message::Ask do
2
+ let(:message_type) { Message::Ask::TYPE_CODE }
3
+ let(:node_id) { SecureRandom.uuid }
4
+
5
+ let(:string) { message_type + node_id }
6
+
7
+ describe '.parse' do
8
+ it 'should parse correctly' do
9
+ message = Message::Ask.parse string
10
+
11
+ expect(message).to be_a Message::Ask
12
+ expect(message.node_id).to eq node_id
13
+ end
14
+ end
15
+
16
+ describe '#to_s' do
17
+ it 'should serialize correctly' do
18
+ serialized = Message::Ask.new(node_id).to_s
19
+
20
+ expect(serialized).to eq string
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ RSpec.describe Message::Command do
2
+ let(:type_code) { Message::Command::TYPE_CODE }
3
+
4
+ let(:sender) { SecureRandom.uuid }
5
+ let(:commandee_id) { SecureRandom.uuid }
6
+
7
+ let(:args) { { thing: 'puppy' } }
8
+ let(:details) { { name: 'TestCommand', args: args } }
9
+ let(:binary_details) { Marshal.dump(details) }
10
+ let(:string) { type_code + sender + commandee_id + binary_details }
11
+
12
+ let(:message) { Message::Command.new(sender, commandee_id, details) }
13
+
14
+ describe '.parse' do
15
+ it 'should parse correctly' do
16
+ message = Message::Command.parse string
17
+
18
+ expect(message).to be_a Message::Command
19
+ expect(message.sender).to eq sender
20
+ expect(message.commandee_id).to eq commandee_id
21
+ expect(message.details).to eq details
22
+ end
23
+ end
24
+
25
+ describe '#name' do
26
+ it 'should return the correct name' do
27
+ expect(message.name).to eq 'TestCommand'
28
+ end
29
+ end
30
+
31
+ describe '#to_command' do
32
+ let(:command_instance) { double }
33
+ let(:command_klass) { spy(new: command_instance) }
34
+
35
+ it 'should build a Command object' do
36
+ stub_const 'TestCommand', command_klass
37
+
38
+ expect(message.to_command).to eq command_instance
39
+ expect(command_klass).to have_received(:new).with args
40
+ end
41
+ end
42
+
43
+ describe '#to_s' do
44
+ it 'should serialize correctly' do
45
+ serialized = message.to_s
46
+
47
+ expect(serialized).to eq string
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ RSpec.describe Message::CreateAggregate do
2
+ let(:sender) { SecureRandom.uuid }
3
+ let(:id) { SecureRandom.uuid }
4
+ let(:type) { 'Test' }
5
+
6
+ let(:string) { Message::CreateAggregate::TYPE_CODE + sender + id + type }
7
+
8
+ let(:message) { Message::CreateAggregate.new(sender, id, type) }
9
+
10
+ describe '.parse' do
11
+ it 'should parse correctly' do
12
+ message = Message::CreateAggregate.parse string
13
+
14
+ expect(message).to be_a Message::CreateAggregate
15
+ expect(message.sender).to eq sender
16
+ expect(message.id).to eq id
17
+ expect(message.type).to eq type
18
+ end
19
+ end
20
+
21
+ describe '#to_s' do
22
+ it 'should serialize correctly' do
23
+ serialized = message.to_s
24
+
25
+ expect(serialized).to eq string
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Message::Endpoint do
2
+ let(:message_type) { Message::Endpoint::TYPE_CODE }
3
+ let(:endpoint) { SecureRandom.uuid }
4
+
5
+ let(:string) { message_type + endpoint }
6
+
7
+ describe '.parse' do
8
+ it 'should parse correctly' do
9
+ message = Message::Endpoint.parse string
10
+
11
+ expect(message).to be_a Message::Endpoint
12
+ expect(message.endpoint).to eq endpoint
13
+ end
14
+ end
15
+
16
+ describe '#to_s' do
17
+ it 'should serialize correctly' do
18
+ serialized = Message::Endpoint.new(endpoint).to_s
19
+
20
+ expect(serialized).to eq string
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe Message::Events do
2
+ EVENTS_TYPE_CODE = Message::Events::TYPE_CODE
3
+
4
+ let(:id) { SecureRandom.uuid }
5
+
6
+ let(:event1) { Event.new :tested_pizza, Time.new, foo: 'bar' }
7
+ let(:event2) { Event.new :tested_system, Time.new, bar: 'foo' }
8
+ let(:events) { [event1, event2] }
9
+
10
+ let(:binary_events) do
11
+ events.map { |event| EventSerializer.serialize event }.join
12
+ end
13
+ let(:string) { EVENTS_TYPE_CODE + id + binary_events }
14
+
15
+ let(:message) { Message::Events.new(id, events) }
16
+
17
+ describe '.parse' do
18
+ it 'should parse correctly' do
19
+ message = Message::Events.parse string
20
+
21
+ parsed_events = message.events.to_a
22
+
23
+ expect(message).to be_a Message::Events
24
+ expect(message.id).to eq id
25
+ expect(parsed_events.first).to eq events.first
26
+ expect(parsed_events.last).to eq events.last
27
+ end
28
+ end
29
+
30
+ describe '#to_s' do
31
+ it 'should serialize correctly' do
32
+ serialized = message.to_s
33
+
34
+ expect(serialized).to eq string
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ RSpec.describe Message::GetEvents do
2
+ let(:message_type) { Message::GetEvents::TYPE_CODE }
3
+ let(:sender) { SecureRandom.uuid }
4
+ let(:id) { SecureRandom.uuid }
5
+ let(:from_version) { 0 }
6
+
7
+ let(:string) { message_type + sender + id + from_version.to_s }
8
+
9
+ describe '.parse' do
10
+ it 'should parse correctly' do
11
+ message = Message::GetEvents.parse string
12
+
13
+ expect(message).to be_a Message::GetEvents
14
+ expect(message.sender).to eq sender
15
+ expect(message.id).to eq id
16
+ expect(message.from_version).to eq from_version
17
+ end
18
+ end
19
+
20
+ describe '#to_s' do
21
+ it 'should serialize correctly' do
22
+ serialized = Message::GetEvents.new(sender, id, from_version).to_s
23
+
24
+ expect(serialized).to eq string
25
+ end
26
+
27
+ it 'should use 0 as a default from_version' do
28
+ serialized = Message::GetEvents.new(sender, id, nil).to_s
29
+
30
+ expect(serialized).to eq string
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Message::Heartbeat do
2
+ let(:message_type) { Message::Heartbeat::TYPE_CODE }
3
+ let(:sender) { SecureRandom.uuid }
4
+
5
+ let(:string) { message_type + sender }
6
+
7
+ describe '.parse' do
8
+ it 'should parse correctly' do
9
+ message = Message::Heartbeat.parse string
10
+
11
+ expect(message).to be_a Message::Heartbeat
12
+ expect(message.sender).to eq sender
13
+ end
14
+ end
15
+
16
+ describe '#to_s' do
17
+ it 'should serialize correctly' do
18
+ serialized = Message::Heartbeat.new(sender).to_s
19
+
20
+ expect(serialized).to eq string
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ RSpec.describe Message::InvalidTarget do
2
+ let(:message_type) { Message::InvalidTarget::TYPE_CODE }
3
+
4
+ let(:string) { message_type }
5
+
6
+ describe '.new' do
7
+ it 'should reuse the same singleton object' do
8
+ expect(Message::InvalidTarget.new.object_id).to eq \
9
+ Message::InvalidTarget.new.object_id
10
+ end
11
+ end
12
+
13
+ describe '.parse' do
14
+ it 'should parse correctly' do
15
+ message = Message::InvalidTarget.parse string
16
+
17
+ expect(message).to be_a Message::InvalidTarget
18
+ end
19
+ end
20
+
21
+ describe '#to_s' do
22
+ it 'should serialize correctly' do
23
+ serialized = Message::InvalidTarget.new.to_s
24
+
25
+ expect(serialized).to eq string
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ RSpec.describe Message::OK do
2
+ let(:message_type) { Message::OK::TYPE_CODE }
3
+
4
+ let(:string) { message_type }
5
+
6
+ describe '.new' do
7
+ it 'should reuse the same singleton object' do
8
+ expect(Message::OK.new.object_id).to eq Message::OK.new.object_id
9
+ end
10
+ end
11
+
12
+ describe '.parse' do
13
+ it 'should parse correctly' do
14
+ message = Message::OK.parse string
15
+
16
+ expect(message).to be_a Message::OK
17
+ end
18
+ end
19
+
20
+ describe '#to_s' do
21
+ it 'should serialize correctly' do
22
+ serialized = Message::OK.new.to_s
23
+
24
+ expect(serialized).to eq string
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Message::PublisherEndpointInquiry do
2
+ let(:message_type) { Message::PublisherEndpointInquiry::TYPE_CODE }
3
+ let(:sender) { SecureRandom.uuid }
4
+
5
+ let(:string) { message_type + sender }
6
+
7
+ describe '.parse' do
8
+ it 'should parse correctly' do
9
+ message = Message::PublisherEndpointInquiry.parse string
10
+
11
+ expect(message).to be_a Message::PublisherEndpointInquiry
12
+ expect(message.sender).to eq sender
13
+ end
14
+ end
15
+
16
+ describe '#to_s' do
17
+ it 'should serialize correctly' do
18
+ serialized = Message::PublisherEndpointInquiry.new(sender).to_s
19
+
20
+ expect(serialized).to eq string
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ RSpec.describe Message::Query do
2
+ let(:type_code) { Message::Query::TYPE_CODE }
3
+
4
+ let(:sender) { SecureRandom.uuid }
5
+ let(:queryable_id) { SecureRandom.uuid }
6
+
7
+ let(:args) { { thing: 'puppy' } }
8
+ let(:details) { { name: 'TestQuery', args: args } }
9
+ let(:binary_details) { Marshal.dump details }
10
+ let(:string) { type_code + sender + queryable_id + binary_details }
11
+
12
+ let(:message) { Message::Query.new(sender, queryable_id, details) }
13
+
14
+ describe '.parse' do
15
+ it 'should parse correctly' do
16
+ message = Message::Query.parse string
17
+
18
+ expect(message).to be_a Message::Query
19
+ expect(message.sender).to eq sender
20
+ expect(message.queryable_id).to eq queryable_id
21
+ expect(message.details).to eq details
22
+ end
23
+ end
24
+
25
+ describe '#name' do
26
+ it 'should return the correct name' do
27
+ expect(message.name).to eq 'TestQuery'
28
+ end
29
+ end
30
+
31
+ describe '#to_query' do
32
+ let(:query_instance) { double }
33
+ let(:query_klass) { spy(new: query_instance) }
34
+
35
+ it 'should build a Query object' do
36
+ stub_const 'TestQuery', query_klass
37
+
38
+ expect(message.to_query).to eq query_instance
39
+ expect(query_klass).to have_received(:new).with args
40
+ end
41
+ end
42
+
43
+ describe '#to_s' do
44
+ it 'should serialize correctly' do
45
+ serialized = message.to_s
46
+
47
+ expect(serialized).to eq string
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+ RSpec.describe Message::StartSaga do
2
+ let(:sender) { SecureRandom.uuid }
3
+ let(:id) { SecureRandom.uuid }
4
+
5
+ let(:args) { { thing: 'puppy' } }
6
+ let(:details) { { name: 'TestSaga', args: args } }
7
+ let(:binary_details) { Marshal.dump details }
8
+ let(:type_code) { Message::StartSaga::TYPE_CODE }
9
+ let(:string) { type_code + sender + id + binary_details }
10
+
11
+ let(:message) { Message::StartSaga.new(sender, id, details) }
12
+
13
+ describe '.parse' do
14
+ it 'should parse correctly' do
15
+ message = Message::StartSaga.parse string
16
+
17
+ expect(message).to be_a Message::StartSaga
18
+ expect(message.sender).to eq sender
19
+ expect(message.id).to eq id
20
+ expect(message.details).to eq details
21
+ end
22
+ end
23
+
24
+ describe '#name' do
25
+ it 'should return the correct name' do
26
+ expect(message.name).to eq 'TestSaga'
27
+ end
28
+ end
29
+
30
+ describe '#to_s' do
31
+ it 'should serialize correctly' do
32
+ serialized = message.to_s
33
+
34
+ expect(serialized).to eq string
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ RSpec.describe Message::UnhandledOperation do
2
+ let(:message_type) { Message::UnhandledOperation::TYPE_CODE }
3
+
4
+ let(:string) { message_type }
5
+
6
+ describe '.new' do
7
+ it 'should reuse the same singleton object' do
8
+ expect(Message::UnhandledOperation.new.object_id).to eq \
9
+ Message::UnhandledOperation.new.object_id
10
+ end
11
+ end
12
+
13
+ describe '.parse' do
14
+ it 'should parse correctly' do
15
+ message = Message::UnhandledOperation.parse string
16
+
17
+ expect(message).to be_a Message::UnhandledOperation
18
+ end
19
+ end
20
+
21
+ describe '#to_s' do
22
+ it 'should serialize correctly' do
23
+ serialized = Message::UnhandledOperation.new.to_s
24
+
25
+ expect(serialized).to eq string
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ RSpec.describe Message::UnknownOperation do
2
+ let(:message_type) { Message::UnknownOperation::TYPE_CODE }
3
+
4
+ let(:string) { message_type }
5
+
6
+ describe '.new' do
7
+ it 'should reuse the same singleton object' do
8
+ expect(Message::UnknownOperation.new.object_id).to eq \
9
+ Message::UnknownOperation.new.object_id
10
+ end
11
+ end
12
+
13
+ describe '.parse' do
14
+ it 'should parse correctly' do
15
+ message = Message::UnknownOperation.parse string
16
+
17
+ expect(message).to be_a Message::UnknownOperation
18
+ end
19
+ end
20
+
21
+ describe '#to_s' do
22
+ it 'should serialize correctly' do
23
+ serialized = Message::UnknownOperation.new.to_s
24
+
25
+ expect(serialized).to eq string
26
+ end
27
+ end
28
+ end