From a7ff82e1c4b43d85de83a529fc5f4c93783f1c92 Mon Sep 17 00:00:00 2001 From: Khemissi Amir <amir.khemissi@insat.ucar.tn> Date: Wed, 14 Jun 2023 20:16:44 +0100 Subject: [PATCH] Added expected scenarios to RecordingCreator spec. (#5229) * Added missing tests. * Met expected scenarios. --- app/services/recording_creator.rb | 26 +- spec/services/recording_creator_spec.rb | 357 ++++++++++++++++++------ 2 files changed, 291 insertions(+), 92 deletions(-) diff --git a/app/services/recording_creator.rb b/app/services/recording_creator.rb index c13cbe56..cde51b13 100644 --- a/app/services/recording_creator.rb +++ b/app/services/recording_creator.rb @@ -23,7 +23,10 @@ class RecordingCreator def call meeting_id = @recording[:metadata][:meetingId] || @recording[:meetingID] - room_id = Room.find_by(meeting_id:).id + room_id = Room.find_by(meeting_id:)&.id + + raise ActiveRecord::RecordNotFound if room_id.nil? + visibility = get_recording_visibility(recording: @recording) # Get length of presentation format(s) @@ -49,9 +52,13 @@ class RecordingCreator # Returns the visibility of the recording (published, unpublished or protected) def get_recording_visibility(recording:) - return Recording::VISIBILITIES[:protected] if recording[:protected].to_s == 'true' + list = recording[:metadata][:'gl-listed'].to_s == 'true' + protect = recording[:protected].to_s == 'true' + publish = recording[:published].to_s == 'true' + + visibility = visibility_for(publish:, protect:, list:) - return Recording::VISIBILITIES[:published] if recording[:published].to_s == 'true' + return visibility unless visibility.nil? Recording::VISIBILITIES[:unpublished] end @@ -80,4 +87,17 @@ class RecordingCreator url: recording[:playback][:format][:url]) end end + + # Visibilitiy Map + def visibility_for(publish:, protect:, list:) + params_for = { + { publish: false, protect: false, list: false } => Recording::VISIBILITIES[:unpublished], + { publish: true, protect: false, list: false } => Recording::VISIBILITIES[:published], + { publish: true, protect: false, list: true } => Recording::VISIBILITIES[:public], + { publish: true, protect: true, list: false } => Recording::VISIBILITIES[:protected], + { publish: true, protect: true, list: true } => Recording::VISIBILITIES[:public_protected] + } + + params_for[{ publish:, protect:, list: }] + end end diff --git a/spec/services/recording_creator_spec.rb b/spec/services/recording_creator_spec.rb index 05556dea..1c697d0e 100644 --- a/spec/services/recording_creator_spec.rb +++ b/spec/services/recording_creator_spec.rb @@ -21,54 +21,230 @@ require 'bigbluebutton_api' describe RecordingCreator, type: :service do let(:room) { create(:room) } + let(:bbb_recording) { single_format_recording } - describe '#call' do - it 'creates single recording and format based on response' do - room.update(meeting_id: 'random-1291479') + before { room.update(meeting_id: single_format_recording[:meetingID]) } - described_class.new(recording: single_format_recording).call + describe '#call' do + it 'creates recording if not found on GL based on BBB response' do + expect do + described_class.new(recording: bbb_recording).call + end.to change(Recording, :count).from(0).to(1) - expect(room.recordings.first.record_id).to eq('f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125') - expect(room.recordings.first.formats.count).to eq(1) - expect(room.recordings.first.formats.first.recording_type).to eq('presentation') + expect(room.recordings.first.record_id).to eq(bbb_recording[:recordID]) + expect(room.recordings.first.participants).to eq(bbb_recording[:participants].to_i) + expect(room.recordings.first.recorded_at.to_i).to eq(bbb_recording[:startTime].to_i) end - it 'creates multiple formats based on response' do - room.update(meeting_id: 'random-5678484') + it 'updates recording data if found on GL based on BBB response' do + create(:recording, room:, record_id: bbb_recording[:recordID]) - described_class.new(recording: multiple_formats_recording).call + expect do + described_class.new(recording: bbb_recording).call + end.not_to change(Recording, :count) - expect(room.recordings.first.formats.count).to eq(2) - expect(room.recordings.first.formats.first.recording_type).to eq('presentation') - expect(room.recordings.first.formats.second.recording_type).to eq('podcast') + expect(room.recordings.first.record_id).to eq(bbb_recording[:recordID]) + expect(room.recordings.first.participants).to eq(bbb_recording[:participants].to_i) + expect(room.recordings.first.recorded_at.to_i).to eq(bbb_recording[:startTime].to_i) end it 'does not create duplicate recordings if called more than once' do - room.update(meeting_id: 'random-1291479') + expect do + described_class.new(recording: bbb_recording).call + end.to change(Recording, :count).from(0).to(1) - described_class.new(recording: single_format_recording).call - described_class.new(recording: single_format_recording).call - described_class.new(recording: single_format_recording).call + expect do + described_class.new(recording: bbb_recording).call + end.not_to change(Recording, :count) - expect(room.recordings.count).to eq(1) + expect do + described_class.new(recording: bbb_recording).call + end.not_to change(Recording, :count) end - it 'returns recording protectable attribute as true if the bbb server protected feature is enabled' do - room.update(meeting_id: 'random-1291479') - described_class.new(recording: protected_recording).call - expect(room.recordings.first.protectable).to be(true) + context 'Formats' do + describe 'Single format' do + let(:bbb_recording) { single_format_recording } + + it 'creates single recording and format based on response' do + expect do + described_class.new(recording: bbb_recording).call + end.to change(Recording, :count).from(0).to(1) + + expect(room.recordings.first.formats.count).to eq(1) + expect(room.recordings.first.formats.first.recording_type).to eq('presentation') + expect(room.recordings.first.length).to eq(bbb_recording[:playback][:format][:length]) + end + end + + describe 'Multiple formats' do + let(:bbb_recording) { multiple_formats_recording } + + it 'creates multiple formats based on response' do + expect do + described_class.new(recording: bbb_recording).call + end.to change(Recording, :count).from(0).to(1) + + expect(room.recordings.first.formats.count).to eq(2) + expect(room.recordings.first.formats.first.recording_type).to eq('presentation') + expect(room.recordings.first.formats.second.recording_type).to eq('podcast') + expect(room.recordings.first.length).to eq(bbb_recording[:playback][:format][0][:length]) + end + end end - it 'returns recording protectable attribute as false if the bbb server protected feature is not enabled' do - room.update(meeting_id: 'random-1291479') - described_class.new(recording: single_format_recording).call - expect(room.recordings.first.protectable).to be(false) + context 'Meeting ID' do + describe 'When meta Meeting ID is NOT returned' do + let(:bbb_recording) { without_meta_meeting_id_recording(meeting_id: room.meeting_id) } + + it 'Finds recording room by the response meeting ID' do + expect do + described_class.new(recording: bbb_recording).call + end.not_to raise_error + + expect(room.recordings.first.record_id).to eq(bbb_recording[:recordID]) + expect(room.meeting_id).to eq(bbb_recording[:meetingID]) + expect(room.meeting_id).not_to eq(bbb_recording[:metadata][:meetingId]) + end + end + + describe 'When meta Meeting ID is returned' do + let(:bbb_recording) { with_meta_meeting_id_recording(meeting_id: room.meeting_id) } + + it 'Finds recording room by the response metadata meeting ID' do + expect do + described_class.new(recording: bbb_recording).call + end.not_to raise_error + + expect(room.recordings.first.record_id).to eq(bbb_recording[:recordID]) + expect(room.meeting_id).to eq(bbb_recording[:metadata][:meetingId]) + expect(room.meeting_id).not_to eq(bbb_recording[:meetingID]) + end + end + + describe 'Inexsitent room for the given meeting ID' do + let(:bbb_recording) { without_meta_meeting_id_recording(meeting_id: '404') } + + it 'Fails without upserting recording' do + expect do + described_class.new(recording: bbb_recording).call + end.to raise_error(ActiveRecord::RecordNotFound) + + expect(room.recordings.count).to eq(0) + end + end + end + + context 'Name' do + describe 'When meta name is NOT returned' do + let(:bbb_recording) { without_meta_name_recording } + + it 'sets recording name to response name' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.name).not_to eq(bbb_recording[:metadata][:name]) + expect(room.recordings.first.name).to eq(bbb_recording[:name]) + end + end + + describe 'When meta name is returned' do + let(:bbb_recording) { with_meta_name_recording } + + it 'sets recording name to response metadata name' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.name).not_to eq(bbb_recording[:name]) + expect(room.recordings.first.name).to eq(bbb_recording[:metadata][:name]) + end + end + end + + context 'Protectable' do + describe 'When BBB server protected feature is enabled' do + let(:bbb_recording) { protected_recording } + + it 'returns recording protectable attribute as true' do + described_class.new(recording: bbb_recording).call + expect(room.recordings.first.protectable).to be(true) + end + end + + describe 'When BBB server protected feature is NOT enabled' do + let(:bbb_recording) { single_format_recording } + + it 'returns recording protectable attribute as false if the bbb server protected feature is not enabled' do + described_class.new(recording: bbb_recording).call + expect(room.recordings.first.protectable).to be(false) + end + end + end + + context 'Visibility' do + describe 'Published' do + let(:bbb_recording) { published_recording } + + it 'sets a BBB published recording visibility to "Published"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:published]) + end + end + + describe 'Protected' do + let(:bbb_recording) { protected_recording } + + it 'sets a BBB published recording visibility to "Protected"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:protected]) + end + end + + describe 'Unpublished' do + let(:bbb_recording) { unpublished_recording } + + it 'sets a BBB published recording visibility to "Unpublished"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:unpublished]) + end + end + + describe 'Public' do + let(:bbb_recording) { public_recording } + + it 'sets a BBB public recording visibility to "Public"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:public]) + end + end + + describe 'Public/Protected' do + let(:bbb_recording) { public_protected_recording } + + it 'sets a BBB Public/Protected recording visibility to "Public/Protected"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:public_protected]) + end + end + + describe 'Unkown cases' do + let(:bbb_recording) { unkown_visibility_recording } + + it 'sets a BBB with unkown recording visibility to "Unpublished"' do + described_class.new(recording: bbb_recording).call + + expect(room.recordings.first.visibility).to eq(Recording::VISIBILITIES[:unpublished]) + end + end end end private - def single_format_recording + def dummy_recording(**args) { recordID: 'f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125', meetingID: 'random-1291479', @@ -77,86 +253,89 @@ describe RecordingCreator, type: :service do isBreakout: 'false', published: true, state: 'published', - startTime: 'Wed, 11 May 2022 12:43:48 -0400'.to_datetime, - endTime: 'Wed, 11 May 2022 12:44:20 -0400'.to_datetime, - participants: '1', + startTime: Faker::Time.between(from: 2.days.ago, to: Time.zone.now).to_datetime, + endTime: Faker::Time.between(from: 2.days.ago, to: Time.zone.now).to_datetime, + participants: Faker::Number.within(range: 1..100).to_s, rawSize: '977816', - metadata: { isBreakout: 'false', meetingId: 'random-1291479', meetingName: 'random-1291479' }, + metadata: { isBreakout: 'false' }, size: '305475', playback: { format: { type: 'presentation', url: 'https://test24.bigbluebutton.org/playback/presentation/2.3/f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125', processingTime: '6386', - length: 0, + length: Faker::Number.within(range: 1..60), size: '305475' } }, data: {} - } + }.merge(args) + end + + def single_format_recording + dummy_recording end def multiple_formats_recording - { - recordID: '955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321', - meetingID: 'random-5678484', - internalMeetingID: '955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321', - name: 'random-5678484', - isBreakout: 'false', - published: true, - state: 'published', - startTime: 'Wed, 11 May 2022 15:13:52 -0400'.to_datetime, - endTime: 'Wed, 11 May 2022 15:14:19 -0400'.to_datetime, - participants: '1', - rawSize: '960565', - metadata: { isBreakout: 'false', meetingId: 'random-5678484', meetingName: 'random-5678484' }, - size: '272997', - playback: { - format: [{ - type: 'presentation', - url: 'https://test24.bigbluebutton.org/playback/presentation/2.3/955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321', - processingTime: '5780', - length: 0, - size: '211880' - }, - { - type: 'podcast', - url: 'https://test24.bigbluebutton.org/podcast/955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321/audio.ogg', - processingTime: '0', - length: 0, - size: '61117' - }] + dummy_recording playback: { + format: [{ + type: 'presentation', + url: 'https://test24.bigbluebutton.org/playback/presentation/2.3/955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321', + processingTime: '5780', + length: 0, + size: '211880' }, - data: {} + { + type: 'podcast', + url: 'https://test24.bigbluebutton.org/podcast/955458f326d02d78ef8d27f4fbf5fafb7c2f666a-1652296432321/audio.ogg', + processingTime: '0', + length: 0, + size: '61117' + }] } end + def without_meta_meeting_id_recording(meeting_id:) + dummy_recording meetingID: meeting_id + end + + def with_meta_meeting_id_recording(meeting_id:) + dummy_recording meetingID: "NOT_#{meeting_id}", metadata: { isBreakout: 'false', meetingId: meeting_id } + end + + def without_meta_name_recording + name = Faker::Name.name + + dummy_recording name:, metadata: { isBreakout: 'false' } + end + + def with_meta_name_recording + name = Faker::Name.name + + dummy_recording name: "WRONG_#{name}", metadata: { isBreakout: 'false', name: } + end + def protected_recording - { - recordID: 'f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125', - meetingID: 'random-1291479', - internalMeetingID: 'f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125', - name: 'random-1291479', - isBreakout: 'false', - published: true, - protected: true, - state: 'published', - startTime: 'Wed, 11 May 2022 12:43:48 -0400'.to_datetime, - endTime: 'Wed, 11 May 2022 12:44:20 -0400'.to_datetime, - participants: '1', - rawSize: '977816', - metadata: { isBreakout: 'false', meetingId: 'random-1291479', meetingName: 'random-1291479' }, - size: '305475', - playback: { - format: { - type: 'presentation', - url: 'https://test24.bigbluebutton.org/playback/presentation/2.3/f0e2be4518868febb0f381ebe7d46ae61364ef1e-1652287428125', - processingTime: '6386', - length: 0, - size: '305475' - } - }, - data: {} - } + dummy_recording published: true, protected: true, metadata: { isBreakout: 'false', 'gl-listed': [false, nil].sample } + end + + def published_recording + dummy_recording published: true, protected: false, metadata: { isBreakout: 'false', 'gl-listed': [false, nil].sample } + end + + def unpublished_recording + dummy_recording published: false, protected: false, metadata: { isBreakout: 'false', 'gl-listed': [false, nil].sample } + end + + def public_recording + dummy_recording published: true, protected: false, metadata: { isBreakout: 'false', 'gl-listed': true } + end + + def public_protected_recording + dummy_recording published: true, protected: true, metadata: { isBreakout: 'false', 'gl-listed': true } + end + + def unkown_visibility_recording + dummy_recording published: false, protected: [true, false].sample, metadata: { isBreakout: 'false', 'gl-listed': [true, false].sample } end end -- GitLab