Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Layout/EmptyLinesAroundBlockBody:
Layout/ExtraSpacing:
Enabled: false

Layout/MultilineMethodCallIndentation:
Enabled: false

Layout/EmptyLinesAroundClassBody:
Enabled: false

Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ gemspec
group :development, :test do
gem "rails", '>= 6.1.4'
gem "rspec-rails"
gem "pry", platform: :mri, require: false
gem "pry-byebug", platform: :mri, require: false
gem 'rubocop'
gem 'yard'
Expand Down
7 changes: 3 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -221,12 +221,12 @@ GEM
parallel (1.20.1)
parser (3.0.1.1)
ast (~> 2.4.1)
pry (0.14.1)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-byebug (3.8.0)
pry-byebug (3.9.0)
byebug (~> 11.0)
pry (~> 0.10)
pry (~> 0.13.0)
public_suffix (4.0.6)
queue-bus (0.12.0)
multi_json
Expand Down Expand Up @@ -366,7 +366,6 @@ DEPENDENCIES
event_source!
faker
mongoid
pry
pry-byebug
rails (>= 6.1.4)
rspec-rails
Expand Down
17 changes: 12 additions & 5 deletions lib/event_source/async_api/channel_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,35 @@ class ChannelItem < Dry::Struct
# MUST be in the format of a Channel Item Object. If there are conflicts between the
# referenced definition and this Channel Item's definition, the behavior is undefined.
# @return [String]
attribute :ref, Types::String.meta(omittable: true)
attribute :ref, Types::String.optional.meta(omittable: true)

# @!attribute [r] description
# An optional description of this channel item
# @return [String]
attribute :description, Types::String.meta(omittable: true)
attribute :description, Types::String.optional.meta(omittable: true)

# @!attribute [r] subscribe
# A definition of the Subscribe operation
# @return [Operation]
attribute :subscribe, SubscribeOperation.meta(omittable: true)
attribute :subscribe,
EventSource::AsyncApi::SubscribeOperation.optional.meta(
omittable: true
)

# @!attribute [r] publish
# A definition of the Publish operation
# @return [Operation]
attribute :publish, PublishOperation.meta(omittable: true)
attribute :publish,
EventSource::AsyncApi::PublishOperation.optional.meta(
omittable: true
)

# @!attribute [r] url
# A map of the parameters included in the channel name.
# It SHOULD be present only when using channels with expressions
# @return [Parameter]
attribute :parameters, Parameter.meta(omittable: true)
attribute :parameters,
EventSource::AsyncApi::Parameter.optional.meta(omittable: true)

# @!attribute [r] bindings
# A map where the keys describe the name of the protocol and the
Expand Down
26 changes: 20 additions & 6 deletions lib/event_source/async_api/contracts/channel_item_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,27 @@ class ChannelItemContract < Contract
params do
required(:id).value(:string)
optional(:ref).value(:string)
optional(:subscribe).value(:hash)
optional(:publish).value(:hash)
optional(:subscribe).value(
EventSource::AsyncApi::Contracts::SubscribeOperationContract.params
)
optional(:publish).value(
EventSource::AsyncApi::Contracts::PublishOperationContract.params
)
optional(:description).value(:string)
optional(:parameters).value(Types::HashOrNil)
optional(:bindings).hash { optional(:amqp).maybe(:hash) }
end

rule(:subscribe) do
if key? && value
validation_result = SubscribeOperationContract.new.call(value)
validation_result =
EventSource::AsyncApi::Contracts::SubscribeOperationContract.new
.call(value)
if validation_result&.failure?
key.failure(text: 'invalid subscribe operation', error: validation_result.errors.to_h)
key.failure(
text: 'invalid subscribe operation',
error: validation_result.errors.to_h
)
else
values.data.merge(subscribe: validation_result.values.to_h)
end
Expand All @@ -37,9 +46,14 @@ class ChannelItemContract < Contract

rule(:publish) do
if key? && value
validation_result = PublishOperationContract.new.call(value)
validation_result =
EventSource::AsyncApi::Contracts::PublishOperationContract.new
.call(value)
if validation_result&.failure?
key.failure(text: 'invalid publish operation', error: validation_result.errors.to_h)
key.failure(
text: 'invalid publish operation',
error: validation_result.errors.to_h
)
else
values.data.merge(publish: validation_result.values.to_h)
end
Expand Down
94 changes: 48 additions & 46 deletions lib/event_source/async_api/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,15 @@ module Types
send(:include, Dry.Types)
include Dry::Logic

# UriKind =
# Types.Constructor(::URI) do |val|
# binding.pry
# (val.is_a? ::URI) ? val : ::URI.parse(val)
# end
UriKind =
Types.Constructor(EventSource::Uris::Uri) do |val|
EventSource::Uris::Uri.new(uri: val)
end

# UriKind = Types.Constructor(::URI, &:parse)
UrlKind = UriKind

# TypeContainer = Dry::Schema::TypeContainer.new
# TypeContainer.register('params.uri', UriKind)

Email =
Coercible::String.constrained(
format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
)
AmqpBindingVersionKind =
Types::Coercible::String.default('0.2.0').enum('0.2.0')

Emails = Array.of(Email)
HashOrNil = Types::Hash | Types::Nil
StringOrNil = Types::String | Types::Nil
CallableDateTime = Types::DateTime.default { DateTime.now }
PositiveInteger = Coercible::Integer.constrained(gteq: 0)

SecuritySchemeKind =
Coercible::Symbol.enum(
:user_password,
:api_key,
:x509,
:symmetric_encryption,
:asymmetric_encryption,
:http_api_key,
:http,
:oauth2,
:open_id_connect
)
ChannelTypeKind =
Types::Coercible::Symbol
.default(:routing_key)
.enum(:routing_key, :queue)

ComponentTypes =
Coercible::Symbol.enum(
Expand All @@ -65,11 +35,14 @@ module Types
:operation_bindings,
:message_bindings
)
Vhost = Types::Coercible::String.default('/')
ChannelTypeKind =
Types::Coercible::Symbol
.default(:routing_key)
.enum(:routing_key, :queue)

Email =
Coercible::String.constrained(
format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
)

Emails = Array.of(Email)

ExchangeTypeKind =
Types::Coercible::Symbol.enum(
:topic,
Expand All @@ -78,15 +51,44 @@ module Types
:direct,
:headers
)

HashOrNil = Types::Hash | Types::Nil

MessageDeliveryModeKind = Types::Coercible::Integer.enum(1, 2)

OperationNameType = Types::String | Types::Symbol

PositiveInteger = Coercible::Integer.constrained(gteq: 0)

QueueName = Types::Coercible::String

RoutingKeyKind = Types::Coercible::String

RoutingKeyKinds = Types::Array.of(RoutingKeyKind)
QueueName = Types::Coercible::String
AmqpBindingVersionKind =
Types::Coercible::String.default('0.2.0').enum('0.2.0')

OperationNameType = Types::String | Types::Symbol
# PatternedFieldName = String.constrained(format: /^[A-Za-z0-9_\-]+$/)
SecuritySchemeKind =
Coercible::Symbol.enum(
:user_password,
:api_key,
:x509,
:symmetric_encryption,
:asymmetric_encryption,
:http_api_key,
:http,
:oauth2,
:open_id_connect
)

StringOrNil = Types::String | Types::Nil

UriKind =
Types.Constructor(EventSource::Uris::Uri) do |val|
EventSource::Uris::Uri.new(uri: val)
end

UrlKind = UriKind

Vhost = Types::Coercible::String.default('/')
end
end
end
26 changes: 26 additions & 0 deletions spec/event_source/async_api/channel_item_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe EventSource::AsyncApi::ChannelItem do
subject { described_class }

let(:id) { 'publish_operation_name' }

let(:required_params) { { id: id } }

context 'without required params' do
it 'should fail validation' do
expect { described_class.new({}) }.to raise_error Dry::Struct::Error
end
end

context 'with required params' do
it 'should pass validation' do
result = described_class.new(required_params)

expect(result).to be_a described_class
expect(result.to_h).to eq required_params
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

require 'spec_helper'
require 'config_helper'
require 'shared_contexts/amqp/connection.rb'
require 'shared_contexts/amqp/channel_item.rb'
require 'pry'
require 'shared_contexts/amqp/connection'
require 'shared_contexts/amqp/channel_item'

class LogService
include EventSource::Logging
Expand All @@ -15,7 +14,7 @@ class ExampleSubscriber
include ::EventSource::Subscriber[amqp: 'spec.crm_contact_created']
extend EventSource::Logging

subscribe(:on_crm_sugarcrm_contacts_contact_created) do |delivery_info, _metadata, response|
subscribe(:on_crm_sugarcrm_contacts_contact_created) do |delivery_info, _metadata, _response|
def method_one(msg)
method_one(msg)
end
Expand Down Expand Up @@ -93,7 +92,7 @@ def method_one(msg)
sleep 1

match_found = false
while true
loop do
match_found = @log_output.readline&.match(/ERROR EventSource : Consumer processed message. Failed and message rejected with exception/)
break if match_found
end
Expand Down