module PlatformSdk module SpecSupport RSpec.shared_examples 'DataPipelineable' do |params = {}| let(:shared_params) { params } let(:record) { build(described_class.to_s.underscore.to_sym) } let(:data_pipeline_client) { double(PlatformSdk::DataPipeline::Client) } before do allow(PlatformSdk::DataPipeline::Client).to receive(:new).and_return(data_pipeline_client) allow(data_pipeline_client).to receive(:post) Timecop.freeze(DateTime.parse('2024-06-09 04:20:00')) end after { Timecop.return } context 'create' do it 'posts a copy of our data to the data pipeline' do record.save! expect(data_pipeline_client).to have_received(:post).once.with(hash_including( noun: described_class.pipeline_noun, data: record.pipeline_data('created'), meta: described_class.pipeline_meta, envelope_version: '1.0.0', message_timestamp: Time.current.utc.iso8601, identifiers: { id: record.id }, )) end end context 'destroy' do it 'posts a copy of our data to the data pipeline' do record.save! record.destroy expect(data_pipeline_client).to have_received(:post).once.with(hash_including( noun: described_class.pipeline_noun, data: record.pipeline_data('destroyed'), meta: described_class.pipeline_meta, envelope_version: '1.0.0', message_timestamp: Time.current.utc.iso8601, identifiers: { id: record.id } )) end end context 'update' do before do record.save! end context 'after an update' do it 'posts a copy of our data to the data pipeline' do column = column_to_update(record) unless column.nil? update_record(record, column) expect(data_pipeline_client).to have_received(:post).once.with(hash_including( noun: described_class.pipeline_noun, data: record.pipeline_data('modified'), meta: described_class.pipeline_meta, envelope_version: '1.0.0', message_timestamp: Time.current.utc.iso8601, identifiers: { id: record.id }, )) end end end context 'after an update that does not change data' do let(:action) { 'modified' } it 'does not post to the data pipeline' do record.save! column = column_to_update(record) update_record(record, column) record.save! expect(data_pipeline_client).to have_received(:post).once.with(hash_including( noun: described_class.pipeline_noun, data: record.pipeline_data('modified'), meta: described_class.pipeline_meta, envelope_version: '1.0.0', message_timestamp: Time.current.utc.iso8601, identifiers: { id: record.id } )) end end end def column_to_update(record) %i[string integer boolean].each do |type| columns_to_update = record.class.columns.select { |c| c.sql_type_metadata.type == type && !c.name.match?(/(_id|_type)$/) && c.name != 'id' } return columns_to_update.first.name if columns_to_update.any? end nil end def update_record(record, column) if shared_params[:update_method] send(shared_params[:update_method], record) return end new_record = build(described_class.to_s.underscore.to_sym) column_value = record[column] column_class = column_value.class case column_class.to_s when 'Integer' record.update!(column => 69) when 'TrueClass', 'FalseClass' record.update!(column => !record[column]) else record.update!(column => new_record[column]) end end describe '#pipeline_payload' do %w[created modified destroyed].each do |action| context "when action is #{action}" do let(:action) { action } let(:pipeline_payload) do { "noun": described_class.pipeline_noun, "identifiers": { "id": record.id }, "meta": described_class.pipeline_meta, "data": data, "envelope_version": '1.0.0', "message_timestamp": Time.current.utc.iso8601 } end let(:data) do record.attributes.symbolize_keys .merge(record.pipeline_additional_attributes) .except(*record.pipeline_excluded_attributes) .merge(action:) end it 'returns the expected payload' do expect(record.pipeline_payload(action)).to eq(pipeline_payload) end end end end end end end