From 43eb684f835ea0acd0c661ab90b82fc941f5c751 Mon Sep 17 00:00:00 2001 From: Denis Talakevich Date: Wed, 10 Jul 2024 15:34:02 +0300 Subject: [PATCH 1/2] add CdrHttpBatch PGQ Processor Closes #1482 --- pgq-processors/processors/cdr_http_batch.rb | 19 ++++++ .../spec/processors/cdr_http_batch_spec.rb | 66 +++++++++++++++++++ .../spec/processors/cdr_http_spec.rb | 32 ++++++--- 3 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 pgq-processors/processors/cdr_http_batch.rb create mode 100644 pgq-processors/spec/processors/cdr_http_batch_spec.rb diff --git a/pgq-processors/processors/cdr_http_batch.rb b/pgq-processors/processors/cdr_http_batch.rb new file mode 100644 index 000000000..7bcd0eaf1 --- /dev/null +++ b/pgq-processors/processors/cdr_http_batch.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'rest-client' +require_relative 'cdr_http_base' + +class CdrHttpBatch < CdrHttpBase + @consumer_name = 'cdr_http' + + def perform_group(events) + permitted_events = events.map { |event| permit_field_for(event) } + perform_http_request(permitted_events) + end + + private + + def http_body(events) + { data: events }.to_json + end +end diff --git a/pgq-processors/spec/processors/cdr_http_batch_spec.rb b/pgq-processors/spec/processors/cdr_http_batch_spec.rb new file mode 100644 index 000000000..d548426af --- /dev/null +++ b/pgq-processors/spec/processors/cdr_http_batch_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'uri' + +require File.join(File.dirname(__FILE__), '../../processors/cdr_http_batch') + +RSpec.describe CdrHttpBatch do + subject do + consumer.perform_group(cdrs) + end + + let(:cdrs) do + [ + { id: 1, duration: 2 }, + { id: 2, duration: 2 } + ] + end + let(:consumer) { CdrHttpBatch.new(TestContext.logger, 'cdr_billing', 'cdr_http_batch', config) } + let(:method) { 'POST' } + let(:cdr_fields) { 'all' } + let(:config) do + { + 'url' => 'https://external-endpoint/api/cdr', + 'method' => method, + 'cdr_fields' => cdr_fields + } + end + + before :each do + allow(consumer).to receive(:config).and_return config + stub_request :post, /#{config['url']}/ + end + + context 'permit all attributes' do + it 'sends POST request with cdrs data' do + subject + expect(WebMock).to have_requested(:post, config['url']).once + expect(WebMock).to have_requested(:post, config['url']).with( + body: { + data: [ + { id: 1, duration: 2 }, + { id: 2, duration: 2 } + ] + } + ) + end + end + + context 'permit array attribute' do + let(:cdr_fields) { ['id'] } + + it 'sends POST request with cdrs data' do + subject + expect(WebMock).to have_requested(:post, config['url']).once + expect(WebMock).to have_requested(:post, config['url']).with( + body: { + data: [ + { id: 1 }, + { id: 2 } + ] + } + ) + end + end +end diff --git a/pgq-processors/spec/processors/cdr_http_spec.rb b/pgq-processors/spec/processors/cdr_http_spec.rb index 49ec049d4..aeeb96caf 100644 --- a/pgq-processors/spec/processors/cdr_http_spec.rb +++ b/pgq-processors/spec/processors/cdr_http_spec.rb @@ -6,13 +6,16 @@ require File.join(File.dirname(__FILE__), '../../processors/cdr_http') RSpec.describe CdrHttp do + subject do + consumer.perform_group(cdrs) + end + let(:cdrs) do [ { id: 1, duration: 2 }, { id: 2, duration: 2 } ] end - let(:consumer) { CdrHttp.new(TestContext.logger, 'cdr_billing', 'cdr_http', config) } let(:method) { 'POST' } let(:cdr_fields) { 'all' } @@ -27,27 +30,36 @@ before :each do allow(consumer).to receive(:config).and_return config stub_request config['method'].downcase.to_sym, /#{config['url']}/ - subject end - subject { consumer.perform_group cdrs } - context 'permit all attributes' do - it { expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1, duration: 2 }) } - it { expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 2, duration: 2 }) } + it 'performs 2 requests' do + subject + expect(WebMock).to have_requested(:post, config['url']).times(2) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1, duration: 2 }) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 2, duration: 2 }) + end end context 'permit array attribute' do let(:cdr_fields) { ['id'] } - it { expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1 }) } - it { expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 2 }) } + it 'performs 2 requests' do + subject + expect(WebMock).to have_requested(:post, config['url']).times(2) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1 }) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 2 }) + end end context 'GET method' do let(:method) { 'GET' } - it { expect(WebMock).to have_requested(:get, "#{config['url']}?#{URI.encode_www_form cdrs[0]}") } - it { expect(WebMock).to have_requested(:get, "#{config['url']}?#{URI.encode_www_form cdrs[1]}") } + it 'performs 2 requests' do + subject + expect(WebMock).to have_requested(:get, /\A#{config['url']}?.+/).times(2) + expect(WebMock).to have_requested(:get, "#{config['url']}?#{URI.encode_www_form cdrs[0]}") + expect(WebMock).to have_requested(:get, "#{config['url']}?#{URI.encode_www_form cdrs[1]}") + end end end From f935c90b79e77255eda16906f8e9ccffb997add9 Mon Sep 17 00:00:00 2001 From: Denis Talakevich Date: Fri, 12 Jul 2024 14:18:10 +0300 Subject: [PATCH 2/2] add data_filters to CDR HTTP and CDR HTTP Batch PGQ Processors Closes #1481 --- pgq-processors/lib/event_filter.rb | 88 +++ pgq-processors/pgq_env.rb | 1 + pgq-processors/processors/cdr_http_base.rb | 18 + pgq-processors/processors/cdr_http_batch.rb | 5 +- pgq-processors/spec/lib/event_filter_spec.rb | 638 ++++++++++++++++++ .../spec/processors/cdr_http_batch_spec.rb | 51 ++ .../spec/processors/cdr_http_spec.rb | 45 ++ pgq-processors/spec/spec_helper.rb | 1 + 8 files changed, 846 insertions(+), 1 deletion(-) create mode 100644 pgq-processors/lib/event_filter.rb create mode 100644 pgq-processors/spec/lib/event_filter_spec.rb diff --git a/pgq-processors/lib/event_filter.rb b/pgq-processors/lib/event_filter.rb new file mode 100644 index 000000000..6ce5f6116 --- /dev/null +++ b/pgq-processors/lib/event_filter.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +class EventFilter + OPERATORS = %i[ + eq not_eq + start_with end_with contains + gt lt gte lte + in not_in + null not_null + true false + ].freeze + + attr_reader :field, :op, :value + + def initialize(field:, op:, value:) + @field = field.to_s + @op = op.to_sym + raise ArgumentError, "Invalid operator: #{@op}" unless OPERATORS.include?(@op) + + @value = value + end + + def match?(event) + send("match_#{op}?", event.transform_keys(&:to_s)) + end + + private + + def match_eq?(event) + event[field] == value + end + + def match_not_eq?(event) + event[field] != value + end + + def match_start_with?(event) + event[field].to_s.start_with?(value.to_s) + end + + def match_end_with?(event) + event[field].to_s.end_with?(value.to_s) + end + + def match_contains?(event) + event[field].to_s.include?(value.to_s) + end + + def match_gt?(event) + !event[field].nil? && event[field] > value + end + + def match_lt?(event) + !event[field].nil? && event[field] < value + end + + def match_gte?(event) + !event[field].nil? && event[field] >= value + end + + def match_lte?(event) + !event[field].nil? && event[field] <= value + end + + def match_in?(event) + value.include?(event[field]) + end + + def match_not_in?(event) + value.exclude?(event[field]) + end + + def match_null?(event) + event[field].nil? + end + + def match_not_null?(event) + !event[field].nil? + end + + def match_true?(event) + event[field] == true + end + + def match_false?(event) + event[field] == false + end +end diff --git a/pgq-processors/pgq_env.rb b/pgq-processors/pgq_env.rb index 83d4929fd..7b197f6d6 100644 --- a/pgq-processors/pgq_env.rb +++ b/pgq-processors/pgq_env.rb @@ -12,6 +12,7 @@ require_relative 'lib/json_each_row_coder' require_relative 'lib/shutdown' require_relative 'lib/amqp_factory' +require_relative 'lib/event_filter' ENV['ROOT_PATH'] ||= Dir.getwd diff --git a/pgq-processors/processors/cdr_http_base.rb b/pgq-processors/processors/cdr_http_base.rb index a13d08620..91fed962e 100644 --- a/pgq-processors/processors/cdr_http_base.rb +++ b/pgq-processors/processors/cdr_http_base.rb @@ -5,18 +5,36 @@ class CdrHttpBase < Pgq::ConsumerGroup AVAILABLE_HTTP_METHODS = %i[post put get patch].freeze + def initialize(...) + super(...) + # data_filters: [{field:, op:, value:}] + if @params['data_filters'].present? + @data_filters = @params['data_filters'].map { |opts| ::EventFilter.new(**opts.transform_keys(&:to_sym)) } + else + @data_filters = nil + end + end + def perform_events(events) perform_group events.map(&:data) end def perform_group(events) events.each do |event| + next unless send_event?(event) + perform_http_request permit_field_for(event) end end private + def send_event?(event) + return true if @data_filters.nil? + + @data_filters.all? { |filter| filter.match?(event) } + end + def http_method :post end diff --git a/pgq-processors/processors/cdr_http_batch.rb b/pgq-processors/processors/cdr_http_batch.rb index 7bcd0eaf1..e5d33bffb 100644 --- a/pgq-processors/processors/cdr_http_batch.rb +++ b/pgq-processors/processors/cdr_http_batch.rb @@ -7,7 +7,10 @@ class CdrHttpBatch < CdrHttpBase @consumer_name = 'cdr_http' def perform_group(events) - permitted_events = events.map { |event| permit_field_for(event) } + events_to_send = events.select { |event| send_event?(event) } + return if events_to_send.empty? + + permitted_events = events_to_send.map { |event| permit_field_for(event) } perform_http_request(permitted_events) end diff --git a/pgq-processors/spec/lib/event_filter_spec.rb b/pgq-processors/spec/lib/event_filter_spec.rb new file mode 100644 index 000000000..6d71e113b --- /dev/null +++ b/pgq-processors/spec/lib/event_filter_spec.rb @@ -0,0 +1,638 @@ +# frozen_string_literal: true + +require File.join(__dir__, '../../lib/event_filter') + +RSpec.describe EventFilter do + describe '#match?' do + subject do + event_filter.match?(event) + end + + let(:event_filter) { described_class.new(**filter_options) } + let(:filter_options) { { field: 'some', op: operator, value: } } + + context 'when operator is eq' do + let(:operator) { 'eq' } + let(:value) { 'test' } + + context 'with event.some is equal to value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + + context 'when value is string but event.some is integer' do + let(:value) { '1' } + let(:event) do + { 'some' => 1 } + end + + it { is_expected.to eq(false) } + end + + context 'when value is integer but event.some is string' do + let(:value) { '1' } + let(:event) do + { 'some' => 1 } + end + + it { is_expected.to eq(false) } + end + end + + context 'with event.some is not equal to value' do + let(:event) do + { 'some' => 'not_test' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is not_eq' do + let(:operator) { 'not_eq' } + let(:value) { 'test' } + + context 'with event.some is equal to value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is not equal to value' do + let(:event) do + { 'some' => 'not_test' } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(true) } + end + end + + context 'when operator is start_with' do + let(:operator) { 'start_with' } + let(:value) { 'te' } + + context 'with event.some start with value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + + context 'when value is integer and event.some is integer' do + let(:value) { 123 } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is string but event.some is integer' do + let(:value) { '123' } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is integer but event.some is string' do + let(:value) { 123 } + let(:event) do + { 'some' => '12345' } + end + + it { is_expected.to eq(true) } + end + end + + context 'with event.some not start with value' do + let(:event) do + { 'some' => 'este' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is end_with' do + let(:operator) { 'end_with' } + let(:value) { 'st' } + + context 'with event.some end with value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + + context 'when value is integer and event.some is integer' do + let(:value) { 45 } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is string but event.some is integer' do + let(:value) { '45' } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is integer but event.some is string' do + let(:value) { 45 } + let(:event) do + { 'some' => '12345' } + end + + it { is_expected.to eq(true) } + end + end + + context 'with event.some not end with value' do + let(:event) do + { 'some' => 'stet' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is contains' do + let(:operator) { 'contains' } + let(:value) { 'es' } + + context 'with event.some contains value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + + context 'when value is integer and event.some is integer' do + let(:value) { 34 } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is string but event.some is integer' do + let(:value) { '34' } + let(:event) do + { 'some' => 12_345 } + end + + it { is_expected.to eq(true) } + end + + context 'when value is integer but event.some is string' do + let(:value) { 34 } + let(:event) do + { 'some' => '12345' } + end + + it { is_expected.to eq(true) } + end + end + + context 'with event.some not contains value' do + let(:event) do + { 'some' => 'tiset' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is gt' do + let(:operator) { 'gt' } + let(:value) { 10 } + + context 'with event.some greater than value' do + let(:event) do + { 'some' => 11 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some less than value' do + let(:event) do + { 'some' => 9 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some equal to value' do + let(:event) do + { 'some' => 10 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is lt' do + let(:operator) { 'lt' } + let(:value) { 10 } + + context 'with event.some less than value' do + let(:event) do + { 'some' => 9 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some greater than value' do + let(:event) do + { 'some' => 11 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some equal to value' do + let(:event) do + { 'some' => 10 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is gte' do + let(:operator) { 'gte' } + let(:value) { 10 } + + context 'with event.some greater than value' do + let(:event) do + { 'some' => 11 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some equal to value' do + let(:event) do + { 'some' => 10 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some less than value' do + let(:event) do + { 'some' => 9 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is lte' do + let(:operator) { 'lte' } + let(:value) { 10 } + + context 'with event.some less than value' do + let(:event) do + { 'some' => 9 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some equal to value' do + let(:event) do + { 'some' => 10 } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some greater than value' do + let(:event) do + { 'some' => 11 } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is in' do + let(:operator) { 'in' } + let(:value) { %w[test test2] } + + context 'with event.some in value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some not in value' do + let(:event) do + { 'some' => 'not_test' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is not_in' do + let(:operator) { 'not_in' } + let(:value) { %w[test test2] } + + context 'with event.some not in value' do + let(:event) do + { 'some' => 'not_test' } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some in value' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is nil' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(true) } + end + end + + context 'when operator is null' do + let(:operator) { 'null' } + let(:value) { nil } + + context 'with event.some is null' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some is not null' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(true) } + end + end + + context 'when operator is not_null' do + let(:operator) { 'not_null' } + let(:value) { nil } + + context 'with event.some is null' do + let(:event) do + { 'some' => nil } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some is not null' do + let(:event) do + { 'some' => 'test' } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is true' do + let(:operator) { 'true' } + let(:value) { true } + + context 'with event.some is true' do + let(:event) do + { 'some' => true } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some is false' do + let(:event) do + { 'some' => false } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + + context 'when operator is false' do + let(:operator) { 'false' } + let(:value) { false } + + context 'with event.some is false' do + let(:event) do + { 'some' => false } + end + + it { is_expected.to eq(true) } + end + + context 'with event.some is true' do + let(:event) do + { 'some' => true } + end + + it { is_expected.to eq(false) } + end + + context 'with event.some key not exist' do + let(:event) { {} } + + it { is_expected.to eq(false) } + end + end + end +end diff --git a/pgq-processors/spec/processors/cdr_http_batch_spec.rb b/pgq-processors/spec/processors/cdr_http_batch_spec.rb index d548426af..39e194eae 100644 --- a/pgq-processors/spec/processors/cdr_http_batch_spec.rb +++ b/pgq-processors/spec/processors/cdr_http_batch_spec.rb @@ -47,6 +47,57 @@ end end + context 'when config has data_filters' do + let(:config) do + super().merge 'data_filters' => [ + { field: 'id', op: 'eq', value: 1 }, + { field: 'duration', op: 'gt', value: 0 } + ] + end + let(:cdrs) do + [ + { id: 1, duration: 2 }, + { id: 1, duration: 3 }, + { id: 2, duration: 2 }, + { id: 1, duration: 0 } + ] + end + + it 'sends POST request with cdrs data' do + subject + expect(WebMock).to have_requested(:post, config['url']).once + expect(WebMock).to have_requested(:post, config['url']).with( + body: { + data: [ + { id: 1, duration: 2 }, + { id: 1, duration: 3 } + ] + } + ) + end + + context 'when all events are filtered out' do + let(:config) do + super().merge 'data_filters' => [ + { field: 'id', op: 'eq', value: 2 }, + { field: 'duration', op: 'gt', value: 0 } + ] + end + let(:cdrs) do + [ + { id: 1, duration: 2 }, + { id: 2, duration: 0 }, + { id: 1, duration: 0 } + ] + end + + it 'sends POST request with cdrs data' do + subject + expect(WebMock).not_to have_requested(:post, config['url']) + end + end + end + context 'permit array attribute' do let(:cdr_fields) { ['id'] } diff --git a/pgq-processors/spec/processors/cdr_http_spec.rb b/pgq-processors/spec/processors/cdr_http_spec.rb index aeeb96caf..c304000ab 100644 --- a/pgq-processors/spec/processors/cdr_http_spec.rb +++ b/pgq-processors/spec/processors/cdr_http_spec.rb @@ -41,6 +41,51 @@ end end + context 'when config has data_filters' do + let(:config) do + super().merge 'data_filters' => [ + { field: 'id', op: 'eq', value: 1 }, + { field: 'duration', op: 'gt', value: 0 } + ] + end + let(:cdrs) do + [ + { id: 1, duration: 2 }, + { id: 1, duration: 3 }, + { id: 2, duration: 2 }, + { id: 1, duration: 0 } + ] + end + + it 'performs 2 requests' do + subject + expect(WebMock).to have_requested(:post, config['url']).times(2) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1, duration: 2 }) + expect(WebMock).to have_requested(:post, config['url']).with(body: { id: 1, duration: 3 }) + end + + context 'when all events are filtered out' do + let(:config) do + super().merge 'data_filters' => [ + { field: 'id', op: 'eq', value: 2 }, + { field: 'duration', op: 'gt', value: 0 } + ] + end + let(:cdrs) do + [ + { id: 1, duration: 2 }, + { id: 2, duration: 0 }, + { id: 1, duration: 0 } + ] + end + + it 'sends POST request with cdrs data' do + subject + expect(WebMock).not_to have_requested(:post, config['url']) + end + end + end + context 'permit array attribute' do let(:cdr_fields) { ['id'] } diff --git a/pgq-processors/spec/spec_helper.rb b/pgq-processors/spec/spec_helper.rb index bde85d701..df32a9bf6 100644 --- a/pgq-processors/spec/spec_helper.rb +++ b/pgq-processors/spec/spec_helper.rb @@ -12,6 +12,7 @@ require TestContext.root_path.join('lib/json_each_row_coder').to_s require TestContext.root_path.join('lib/shutdown').to_s require TestContext.root_path.join('lib/amqp_factory').to_s +require TestContext.root_path.join('lib/event_filter').to_s require 'webmock/rspec' require 'bunny-mock'