diff --git a/react/src/Components/Footer/Components/RoomCreationPasswordDialog.js b/react/src/Components/Footer/Components/RoomCreationPasswordDialog.js index 35d48d6dc..ff2857f74 100644 --- a/react/src/Components/Footer/Components/RoomCreationPasswordDialog.js +++ b/react/src/Components/Footer/Components/RoomCreationPasswordDialog.js @@ -65,6 +65,7 @@ export function RoomCreationPasswordDialog(props) { placeholder="Enter room name" /> */} { + + beforeEach(() => { + // Reset the mock implementation before each test + jest.clearAllMocks(); + }); + + + it('renders without crashing', () => { + render( + + ); + }); + +}); diff --git a/react/src/__tests__/Components/DrawerButton.test.js b/react/src/__tests__/Components/DrawerButton.test.js new file mode 100644 index 000000000..733f54b72 --- /dev/null +++ b/react/src/__tests__/Components/DrawerButton.test.js @@ -0,0 +1,32 @@ +// src/DrawerButton.test.js +import React from 'react'; +import { render } from '@testing-library/react'; +import EffectsDrawer from "../../Components/EffectsDrawer"; +import BecomePublisherConfirmationDialog from "../../Components/BecomePublisherConfirmationDialog"; +import DrawerButton from "../../Components/DrawerButton"; + +// Mock the props +const props = { + handleMessageDrawerOpen: jest.fn(), + handleParticipantListOpen: jest.fn(), + handleEffectsOpen: jest.fn(), + setPublisherRequestListDrawerOpen: jest.fn(), +} + +describe('Drawer Button Component', () => { + + beforeEach(() => { + // Reset the mock implementation before each test + jest.clearAllMocks(); + }); + + + it('renders without crashing', () => { + render( + + ); + }); + +}); diff --git a/react/src/__tests__/Components/Footer/Components/EffectsDrawer.test.js b/react/src/__tests__/Components/EffectsDrawer.test.js similarity index 90% rename from react/src/__tests__/Components/Footer/Components/EffectsDrawer.test.js rename to react/src/__tests__/Components/EffectsDrawer.test.js index 98c11319f..cfdcbbc62 100644 --- a/react/src/__tests__/Components/Footer/Components/EffectsDrawer.test.js +++ b/react/src/__tests__/Components/EffectsDrawer.test.js @@ -1,7 +1,7 @@ // src/EffectsDrawer.test.js import React from 'react'; import { render } from '@testing-library/react'; -import EffectsDrawer from "../../../../Components/EffectsDrawer"; +import EffectsDrawer from "../../Components/EffectsDrawer"; // Mock the props const props = { @@ -28,7 +28,7 @@ jest.mock('react', () => ({ ...jest.requireActual('react'), })); -describe('Camera Button Component', () => { +describe('Effects Drawer Component', () => { beforeEach(() => { // Reset the mock implementation before each test diff --git a/react/src/__tests__/Components/MessageDrawer.test.js b/react/src/__tests__/Components/MessageDrawer.test.js new file mode 100644 index 000000000..e548c6ade --- /dev/null +++ b/react/src/__tests__/Components/MessageDrawer.test.js @@ -0,0 +1,35 @@ +// src/MessageDrawer.test.js +import React from 'react'; +import { render } from '@testing-library/react'; +import EffectsDrawer from "../../Components/EffectsDrawer"; +import BecomePublisherConfirmationDialog from "../../Components/BecomePublisherConfirmationDialog"; +import MessageDrawer from "../../Components/MessageDrawer"; + +// Mock the props +const props = { + handleMessageDrawerOpen: jest.fn(), + handleParticipantListOpen: jest.fn(), + handleEffectsOpen: jest.fn(), + setPublisherRequestListDrawerOpen: jest.fn(), + messages: [], + sendMessage: jest.fn(), + handleSetMessages: jest.fn(), +} + +describe('Message Drawer Component', () => { + + beforeEach(() => { + // Reset the mock implementation before each test + jest.clearAllMocks(); + }); + + + it('renders without crashing', () => { + render( + + ); + }); + +}); diff --git a/test/test_join_leave.py b/test/test_join_leave.py index 1cd554f33..babf489b3 100644 --- a/test/test_join_leave.py +++ b/test/test_join_leave.py @@ -1,6 +1,8 @@ from browser import Browser from selenium.webdriver.common.by import By from rest_helper import RestHelper +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC import subprocess @@ -113,6 +115,16 @@ def join_room_in_new_tab(self, participant, room, play_only=False): assert(meeting_gallery.is_displayed()) return handle + + def open_home_page_in_new_tab(self, participant): + print("url: "+self.url+"/"+self.test_app_name+"/") + app = "/"+self.test_app_name + if self.url.endswith("localhost:3000"): + app = "" + + handle = self.chrome.open_in_new_tab(self.url + app + "/") + + return handle def get_videoTrackAssignments(self, expected_value=None): script = "return window.conference;" @@ -1860,6 +1872,71 @@ def test_theme(self): self.chrome.close_all() + def test_create_meeting_with_password(self): + wait = WebDriverWait(self.chrome, 10) + roomPassword = "123123" + + # create room without password + room = "room"+str(random.randint(100, 999)) + handle_0 = self.open_home_page_in_new_tab("participantA") + + create_meeting_element = wait.until( + EC.element_to_be_clickable((By.XPATH, "//Typography[text()='Create Meeting']")) + ) + + create_meeting_element.click() + + time.sleep(1) + + localVideo = self.chrome.get_element_with_retry(By.ID, 'localVideo') + + assert(localVideo.is_displayed()) + + self.chrome.close_all() + + # join room with password + self.rest_helper + time.sleep(10) + app_settings = self.rest_helper.call_get_app_settings(self.test_app_name) + app_settings["customSettings"] = { + "circle":{ + "roomCreationPassword": roomPassword + } + } + response = self.rest_helper.call_set_app_settings(self.test_app_name, app_settings) + assert(response["success"]) + time.sleep(10) + + room = "room"+str(random.randint(100, 999)) + handle_1 = self.open_home_page_in_new_tab("participantB") + + create_meeting_element = wait.until( + EC.element_to_be_clickable((By.XPATH, "//Typography[text()='Create Meeting']")) + ) + + create_meeting_element.click() + + time.sleep(1) + + input_field = wait.until( + EC.presence_of_element_located((By.ID, "room_creation_password")) + ) + + input_field.send_keys(roomPassword) + + create_room_button = wait.until( + EC.element_to_be_clickable((By.ID, "create_room_button")) + ) + + create_room_button.click() + + time.sleep(1) + + localVideo = self.chrome.get_element_with_retry(By.ID, 'localVideo') + + assert(localVideo.is_displayed()) + + self.chrome.close_all() def test_language(self): room = "room"+str(random.randint(100, 999)) diff --git a/webapp/src/main/java/io/antmedia/enterprise/streamapp/AMSBroadcastManager.java b/webapp/src/main/java/io/antmedia/enterprise/streamapp/AMSBroadcastManager.java index 03481d3f4..44a292682 100644 --- a/webapp/src/main/java/io/antmedia/enterprise/streamapp/AMSBroadcastManager.java +++ b/webapp/src/main/java/io/antmedia/enterprise/streamapp/AMSBroadcastManager.java @@ -1,11 +1,14 @@ package io.antmedia.enterprise.streamapp; +import com.google.gson.Gson; import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.AppSettings; import io.antmedia.datastore.db.DataStore; import io.antmedia.datastore.db.DataStoreFactory; import io.antmedia.datastore.db.IDataStoreFactory; import io.antmedia.datastore.db.types.Broadcast; import io.antmedia.datastore.db.types.BroadcastUpdate; +import io.antmedia.muxer.IAntMediaStreamHandler; import io.antmedia.rest.model.Result; import io.antmedia.rest.RestServiceBase; import org.jetbrains.annotations.NotNull; @@ -21,14 +24,17 @@ public class AMSBroadcastManager implements ApplicationContextAware { private ApplicationContext applicationContext; private AntMediaApplicationAdapter appAdaptor; + private ConferenceRoomSettings conferenceRoomSettings; + private AppSettings appSettings; + private Gson gson = new Gson(); @Override public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; - } - public ApplicationContext getApplicationContext() { - return applicationContext; + IAntMediaStreamHandler app = getApplication(); + appSettings = app.getAppSettings(); + fetchConferenceRoomSettings(); } public AntMediaApplicationAdapter getApplication() { @@ -78,4 +84,39 @@ public boolean updateBroadcastRole(String streamId, String role) { return result; } + + public void fetchConferenceRoomSettings() { + Object circleSettingsString = appSettings.getCustomSetting("circle"); + if (circleSettingsString == null) { + logger.error("Using default settings for Conference Room Settings because no Circle settings in the AppSettings"); + + conferenceRoomSettings = new ConferenceRoomSettings(); + } + else { + try { + conferenceRoomSettings = gson.fromJson(circleSettingsString.toString(), ConferenceRoomSettings.class); + } + catch (Exception e) + { + logger.error("Invalid Conference room settings, using default conference room settings"); + conferenceRoomSettings = new ConferenceRoomSettings(); + } + } + conferenceRoomSettings.init(); + + String participantVisibilityMatrix = appSettings.getParticipantVisibilityMatrix().toString(); + + if (participantVisibilityMatrix != null && conferenceRoomSettings.getParticipantVisibilityMatrix() == null) { + conferenceRoomSettings.setParticipantVisibilityMatrix(participantVisibilityMatrix); + } + + int maxVideoTrackCount = appSettings.getMaxVideoTrackCount(); + + conferenceRoomSettings.setMaxVideoTrackCount(maxVideoTrackCount); + } + + public ConferenceRoomSettings getConferenceRoomSettings() { + return conferenceRoomSettings; + } + } diff --git a/webapp/src/main/java/io/antmedia/enterprise/streamapp/ConferenceRoomSettings.java b/webapp/src/main/java/io/antmedia/enterprise/streamapp/ConferenceRoomSettings.java index e96bc5c42..1cfe0f4ed 100644 --- a/webapp/src/main/java/io/antmedia/enterprise/streamapp/ConferenceRoomSettings.java +++ b/webapp/src/main/java/io/antmedia/enterprise/streamapp/ConferenceRoomSettings.java @@ -1,41 +1,34 @@ package io.antmedia.enterprise.streamapp; +import com.google.gson.annotations.Expose; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.PropertySource; - -import com.google.gson.annotations.Expose; import jakarta.annotation.PostConstruct; -@PropertySource("/WEB-INF/red5-web.properties") + public class ConferenceRoomSettings { protected static Logger logger = LoggerFactory.getLogger(ConferenceRoomSettings.class); - - @Value("${roomCreationPassword:#{null}}") private String roomCreationPassword; - @Expose + @Expose private boolean roomCreationPasswordEnabled = false; - - @Expose + + @Expose private boolean isRecordingFeatureAvailable = false; - @Expose - private String participantVisibilityMatrix; + @Expose + private String participantVisibilityMatrix; @Expose private int maxVideoTrackCount = 6; @PostConstruct public void init() { - roomCreationPasswordEnabled = StringUtils.isNotBlank(roomCreationPassword); - logger.info("roomCreationPasswordEnabled is {}", StringUtils.isNotBlank(roomCreationPassword)); try { Class.forName("io.antmedia.plugin.IMediaPushPlugin"); @@ -46,6 +39,7 @@ public void init() { isRecordingFeatureAvailable = false; } + roomCreationPasswordEnabled = StringUtils.isNotBlank(roomCreationPassword); } diff --git a/webapp/src/main/java/io/antmedia/enterprise/streamapp/WebSocketApplicationHandler.java b/webapp/src/main/java/io/antmedia/enterprise/streamapp/WebSocketApplicationHandler.java index 52647405f..6e5501825 100644 --- a/webapp/src/main/java/io/antmedia/enterprise/streamapp/WebSocketApplicationHandler.java +++ b/webapp/src/main/java/io/antmedia/enterprise/streamapp/WebSocketApplicationHandler.java @@ -122,9 +122,8 @@ private AMSBroadcastManager getAMSBroadcastManager() { } private void setConferenceRoomSettings(){ - if(context != null){ - conferenceRoomSettings = (ConferenceRoomSettings) context.getBean("conferenceRoomSettings"); - } + getAMSBroadcastManager().fetchConferenceRoomSettings(); + conferenceRoomSettings = getAMSBroadcastManager().getConferenceRoomSettings(); } private void setAppSettings() { @@ -323,17 +322,6 @@ private Object getMediaPushPlugin() { } private void responseRoomSettings(Session session) { - - String participantVisibilityMatrix = appSettings.getParticipantVisibilityMatrix().toString(); - - if (participantVisibilityMatrix != null) { - conferenceRoomSettings.setParticipantVisibilityMatrix(participantVisibilityMatrix); - } - - int maxVideoTrackCount = appSettings.getMaxVideoTrackCount(); - - conferenceRoomSettings.setMaxVideoTrackCount(maxVideoTrackCount); - JSONObject jsonResponse = new JSONObject(); jsonResponse.put(WebSocketConstants.COMMAND, WebSocketApplicationConstants.SET_SETTINGS_COMMAND); jsonResponse.put(WebSocketApplicationConstants.SETTINGS, gsonOnlyExposedFields.toJson(conferenceRoomSettings));