From 1f9a9dd1726c8d6e70b36ee273a20bfe6a236eff Mon Sep 17 00:00:00 2001 From: Dan Thomas Date: Sat, 30 Oct 2021 14:50:20 -0400 Subject: [PATCH 1/4] Fix rubocop errors --- .../protocols/amqp/bunny_consumer_handler_spec.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/event_source/protocols/amqp/bunny_consumer_handler_spec.rb b/spec/event_source/protocols/amqp/bunny_consumer_handler_spec.rb index 0a36b290..96032577 100644 --- a/spec/event_source/protocols/amqp/bunny_consumer_handler_spec.rb +++ b/spec/event_source/protocols/amqp/bunny_consumer_handler_spec.rb @@ -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 @@ -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 @@ -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 From cb50dede9a176f2c030ab1e6589617d4cfee0c7e Mon Sep 17 00:00:00 2001 From: Dan Thomas Date: Mon, 1 Nov 2021 08:07:43 -0400 Subject: [PATCH 2/4] Fix pry --- Gemfile | 1 - Gemfile.lock | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 55e26d2d..ef452139 100644 --- a/Gemfile +++ b/Gemfile @@ -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' diff --git a/Gemfile.lock b/Gemfile.lock index a3559182..d65de8f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 @@ -366,7 +366,6 @@ DEPENDENCIES event_source! faker mongoid - pry pry-byebug rails (>= 6.1.4) rspec-rails From 6eb186744fd8df2f6e9de9b280605e6fffb67556 Mon Sep 17 00:00:00 2001 From: Dan Thomas Date: Mon, 1 Nov 2021 10:55:03 -0400 Subject: [PATCH 3/4] Update ChannelItem entity and contract with namespaced attrubutes Add entity spec Organize types --- lib/event_source/async_api/channel_item.rb | 17 +++- .../contracts/channel_item_contract.rb | 26 +++-- lib/event_source/async_api/types.rb | 94 ++++++++++--------- .../async_api/channel_item_spec.rb | 26 +++++ 4 files changed, 106 insertions(+), 57 deletions(-) create mode 100644 spec/event_source/async_api/channel_item_spec.rb diff --git a/lib/event_source/async_api/channel_item.rb b/lib/event_source/async_api/channel_item.rb index c18378b6..63d9c18a 100644 --- a/lib/event_source/async_api/channel_item.rb +++ b/lib/event_source/async_api/channel_item.rb @@ -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 diff --git a/lib/event_source/async_api/contracts/channel_item_contract.rb b/lib/event_source/async_api/contracts/channel_item_contract.rb index 3791b1f1..c46470f3 100644 --- a/lib/event_source/async_api/contracts/channel_item_contract.rb +++ b/lib/event_source/async_api/contracts/channel_item_contract.rb @@ -17,8 +17,12 @@ 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) } @@ -26,9 +30,14 @@ class ChannelItemContract < Contract 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 @@ -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 diff --git a/lib/event_source/async_api/types.rb b/lib/event_source/async_api/types.rb index e1a97523..2f4669b0 100644 --- a/lib/event_source/async_api/types.rb +++ b/lib/event_source/async_api/types.rb @@ -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( @@ -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, @@ -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 diff --git a/spec/event_source/async_api/channel_item_spec.rb b/spec/event_source/async_api/channel_item_spec.rb new file mode 100644 index 00000000..e3246538 --- /dev/null +++ b/spec/event_source/async_api/channel_item_spec.rb @@ -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 From c56af9d4d190b0d915f942c227fece5bc10f928e Mon Sep 17 00:00:00 2001 From: Dan Thomas Date: Mon, 1 Nov 2021 10:59:47 -0400 Subject: [PATCH 4/4] Disable Layout/MultilineMethodCallIndentation --- .rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index e35fac10..8b21a905 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -16,6 +16,9 @@ Layout/EmptyLinesAroundBlockBody: Layout/ExtraSpacing: Enabled: false +Layout/MultilineMethodCallIndentation: + Enabled: false + Layout/EmptyLinesAroundClassBody: Enabled: false