Merge pull request #13627 from antobinary/merge-24
chore: Merging 2.4 into develop branch
This commit is contained in:
commit
b3cc098939
@ -11,7 +11,7 @@ stages:
|
||||
|
||||
# define which docker image to use for builds
|
||||
default:
|
||||
image: gitlab.senfcall.de:5050/senfcall-public/docker-bbb-build:v2021-10-25
|
||||
image: gitlab.senfcall.de:5050/senfcall-public/docker-bbb-build:v2021-11-01
|
||||
|
||||
# This stage uses git to find out since when each package has been unmodified.
|
||||
# it then checks an API endpoint on the package server to find out for which of
|
||||
|
@ -60,6 +60,7 @@ public class ApiParams {
|
||||
public static final String WEBCAMS_ONLY_FOR_MODERATOR = "webcamsOnlyForModerator";
|
||||
public static final String WELCOME = "welcome";
|
||||
public static final String HTML5_INSTANCE_ID = "html5InstanceId";
|
||||
public static final String ROLE = "role";
|
||||
|
||||
public static final String BREAKOUT_ROOMS_ENABLED = "breakoutRoomsEnabled";
|
||||
public static final String BREAKOUT_ROOMS_RECORD = "breakoutRoomsRecord";
|
||||
|
@ -74,6 +74,10 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MeetingService implements MessageListener {
|
||||
private static Logger log = LoggerFactory.getLogger(MeetingService.class);
|
||||
|
||||
@ -1189,6 +1193,13 @@ public class MeetingService implements MessageListener {
|
||||
log.info("Starting Meeting Service.");
|
||||
try {
|
||||
processMessage = true;
|
||||
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "cat /etc/bigbluebutton/bigbluebutton-release | cut -d '=' -f2"});
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||
|
||||
String apiVersionFromFile = reader.readLine();
|
||||
|
||||
paramsProcessorUtil.setBbbVersion(apiVersionFromFile);
|
||||
Runnable messageReceiver = new Runnable() {
|
||||
public void run() {
|
||||
while (processMessage) {
|
||||
|
@ -118,6 +118,9 @@ public class ParamsProcessorUtil {
|
||||
private Integer defaultEndWhenNoModeratorDelayInMinutes = 1;
|
||||
private Integer defaultHtml5InstanceId = 1;
|
||||
|
||||
private String bbbVersion = "";
|
||||
private Boolean allowRevealOfBBBVersion = false;
|
||||
|
||||
private String formatConfNum(String s) {
|
||||
if (s.length() > 5) {
|
||||
/* Reverse conference number.
|
||||
@ -659,6 +662,14 @@ public class ParamsProcessorUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public String getBbbVersion() {
|
||||
return bbbVersion;
|
||||
}
|
||||
|
||||
public Boolean getAllowRevealOfBBBVersion() {
|
||||
return allowRevealOfBBBVersion;
|
||||
}
|
||||
|
||||
public String processWelcomeMessage(String message, Boolean isBreakout) {
|
||||
String welcomeMessage = message;
|
||||
if (StringUtils.isEmpty(message)) {
|
||||
@ -1178,4 +1189,12 @@ public class ParamsProcessorUtil {
|
||||
this.defaultEndWhenNoModeratorDelayInMinutes = value;
|
||||
}
|
||||
|
||||
public void setBbbVersion(String version) {
|
||||
this.bbbVersion = this.allowRevealOfBBBVersion ? version : "";
|
||||
}
|
||||
|
||||
public void setAllowRevealOfBBBVersion(Boolean allowVersion) {
|
||||
this.allowRevealOfBBBVersion = allowVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
|
||||
PASSWORD("password"),
|
||||
GUEST("guest"),
|
||||
AUTH("auth"),
|
||||
CREATE_TIME("createTime");
|
||||
CREATE_TIME("createTime"),
|
||||
ROLE("role");
|
||||
|
||||
private final String value;
|
||||
|
||||
@ -49,6 +50,8 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
|
||||
private String createTimeString;
|
||||
private Long createTime;
|
||||
|
||||
private String role;
|
||||
|
||||
public JoinMeeting(Checksum checksum) {
|
||||
super(checksum);
|
||||
}
|
||||
@ -115,6 +118,14 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateFromParamsMap(Map<String, String[]> params) {
|
||||
if(params.containsKey(Params.MEETING_ID.getValue())) {
|
||||
@ -127,6 +138,7 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
|
||||
if(params.containsKey(Params.GUEST.getValue())) setGuestString(params.get(Params.GUEST.getValue())[0]);
|
||||
if(params.containsKey(Params.AUTH.getValue())) setAuthString(params.get(Params.AUTH.getValue())[0]);
|
||||
if(params.containsKey(Params.CREATE_TIME.getValue())) setCreateTimeString(params.get(Params.CREATE_TIME.getValue())[0]);
|
||||
if(params.containsKey(Params.ROLE.getValue())) setRole(params.get(Params.ROLE.getValue())[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,12 +52,13 @@ public class ResponseBuilder {
|
||||
return new Date(timestamp).toString();
|
||||
}
|
||||
|
||||
public String buildMeetingVersion(String version, String returnCode) {
|
||||
public String buildMeetingVersion(String apiVersion, String bbbVersion, String returnCode) {
|
||||
StringWriter xmlText = new StringWriter();
|
||||
|
||||
Map<String, Object> data = new HashMap<String, Object>();
|
||||
data.put("returnCode", returnCode);
|
||||
data.put("version", version);
|
||||
data.put("apiVersion", apiVersion);
|
||||
data.put("bbbVersion", bbbVersion);
|
||||
|
||||
processData(getTemplate("api-version.ftlx"), data, xmlText);
|
||||
|
||||
|
@ -5,16 +5,16 @@
|
||||
|
||||
meteor-base@1.5.1
|
||||
mobile-experience@1.1.0
|
||||
mongo@1.12.0
|
||||
mongo@1.13.0
|
||||
reactive-var@1.0.11
|
||||
|
||||
standard-minifier-css@1.7.3
|
||||
standard-minifier-js@2.6.1
|
||||
standard-minifier-css@1.7.4
|
||||
standard-minifier-js@2.7.1
|
||||
es5-shim@4.8.0
|
||||
ecmascript@0.15.3
|
||||
ecmascript@0.16.0
|
||||
shell-server@0.5.0
|
||||
|
||||
static-html
|
||||
static-html@1.3.2
|
||||
react-meteor-data
|
||||
http@1.4.2
|
||||
session@1.2.0
|
||||
|
@ -1 +1 @@
|
||||
METEOR@2.3.6
|
||||
METEOR@2.5
|
||||
|
@ -1,5 +1,5 @@
|
||||
allow-deny@1.1.0
|
||||
autoupdate@1.7.0
|
||||
autoupdate@1.8.0
|
||||
babel-compiler@7.7.0
|
||||
babel-runtime@1.5.0
|
||||
base64@1.0.12
|
||||
@ -8,20 +8,20 @@ blaze-tools@1.1.2
|
||||
boilerplate-generator@1.7.1
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.2.1
|
||||
callback-hook@1.3.1
|
||||
callback-hook@1.4.0
|
||||
cfs:reactive-list@0.0.9
|
||||
check@1.3.1
|
||||
ddp@1.4.0
|
||||
ddp-client@2.5.0
|
||||
ddp-common@1.4.0
|
||||
ddp-server@2.4.1
|
||||
ddp-server@2.5.0
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.1
|
||||
dynamic-import@0.7.1
|
||||
ecmascript@0.15.3
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.11.1
|
||||
ecmascript-runtime-server@0.10.1
|
||||
dynamic-import@0.7.2
|
||||
ecmascript@0.16.0
|
||||
ecmascript-runtime@0.8.0
|
||||
ecmascript-runtime-client@0.12.1
|
||||
ecmascript-runtime-server@0.11.0
|
||||
ejson@1.1.1
|
||||
es5-shim@4.8.0
|
||||
fetch@0.1.1
|
||||
@ -34,21 +34,21 @@ id-map@1.1.1
|
||||
inter-process-messaging@0.1.1
|
||||
launch-screen@1.3.0
|
||||
lmieulet:meteor-coverage@3.2.0
|
||||
logging@1.2.0
|
||||
meteor@1.9.3
|
||||
logging@1.3.1
|
||||
meteor@1.10.0
|
||||
meteor-base@1.5.1
|
||||
meteortesting:browser-tests@1.3.4
|
||||
meteortesting:mocha@2.0.2
|
||||
meteortesting:mocha-core@8.0.1
|
||||
minifier-css@1.5.4
|
||||
minifier-js@2.6.1
|
||||
minifier-css@1.6.0
|
||||
minifier-js@2.7.1
|
||||
minimongo@1.7.0
|
||||
mobile-experience@1.1.0
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.5
|
||||
modules@0.16.0
|
||||
modern-browsers@0.1.7
|
||||
modules@0.17.0
|
||||
modules-runtime@0.12.0
|
||||
mongo@1.12.0
|
||||
mongo@1.13.0
|
||||
mongo-decimal@0.1.2
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.8
|
||||
@ -57,7 +57,7 @@ npm-mongo@3.9.1
|
||||
ordered-dict@1.1.0
|
||||
promise@0.12.0
|
||||
random@1.2.0
|
||||
react-fast-refresh@0.1.1
|
||||
react-fast-refresh@0.2.0
|
||||
react-meteor-data@0.2.16
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
@ -69,13 +69,13 @@ session@1.2.0
|
||||
shell-server@0.5.0
|
||||
socket-stream-client@0.4.0
|
||||
spacebars-compiler@1.3.0
|
||||
standard-minifier-css@1.7.3
|
||||
standard-minifier-js@2.6.1
|
||||
standard-minifier-css@1.7.4
|
||||
standard-minifier-js@2.7.1
|
||||
static-html@1.3.2
|
||||
templating-tools@1.2.1
|
||||
tmeasday:check-npm-versions@0.3.2
|
||||
tracker@1.2.0
|
||||
underscore@1.0.10
|
||||
url@1.3.2
|
||||
webapp@1.11.1
|
||||
webapp@1.13.0
|
||||
webapp-hashing@1.1.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh -e
|
||||
#!/bin/sh -ex
|
||||
|
||||
# Please check bigbluebutton/bigbluebutton-html5/dev_local_deployment/README.md
|
||||
|
||||
@ -22,21 +22,18 @@ if [ -d "node_modules" ]; then
|
||||
rm -r node_modules/
|
||||
fi
|
||||
meteor reset
|
||||
meteor npm install --production
|
||||
|
||||
meteor npm ci --production
|
||||
|
||||
sudo chmod 777 /usr/share/meteor
|
||||
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build $UPPER_DESTINATION_DIR --architecture os.linux.x86_64 --allow-superuser
|
||||
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build $UPPER_DESTINATION_DIR --architecture os.linux.x86_64 --allow-superuser --directory
|
||||
|
||||
sudo chown -R meteor:meteor "$UPPER_DESTINATION_DIR"/
|
||||
echo 'stage3'
|
||||
|
||||
|
||||
tar -xzf $UPPER_DESTINATION_DIR/bigbluebutton-html5.tar.gz -C $UPPER_DESTINATION_DIR
|
||||
|
||||
|
||||
cd "$DESTINATION_DIR"/programs/server/ || exit
|
||||
sudo npm i --production
|
||||
sudo npm i
|
||||
|
||||
echo "deployed to $DESTINATION_DIR/programs/server\n\n\n"
|
||||
|
||||
echo "writing $DESTINATION_DIR/mongod_start_pre.sh"
|
||||
|
@ -50,6 +50,7 @@ const PresentationOptionsContainer = ({
|
||||
return (
|
||||
<Styled.RestorePresentationButton
|
||||
icon={`${buttonType}${isLayoutSwapped ? '_off' : ''}`}
|
||||
data-test="restorePresentationButton"
|
||||
label={intl.formatMessage(isLayoutSwapped ? intlMessages.restorePresentationLabel : intlMessages.minimizePresentationLabel)}
|
||||
aria-label={intl.formatMessage(isLayoutSwapped ? intlMessages.restorePresentationLabel : intlMessages.minimizePresentationLabel)}
|
||||
aria-describedby={intl.formatMessage(isLayoutSwapped ? intlMessages.restorePresentationDesc : intlMessages.minimizePresentationDesc)}
|
||||
|
@ -103,7 +103,7 @@ class ExternalVideoModal extends Component {
|
||||
contentLabel={intl.formatMessage(intlMessages.title)}
|
||||
hideBorder
|
||||
>
|
||||
<header data-test="videoModealHeader" className={styles.header}>
|
||||
<header data-test="videoModalHeader" className={styles.header}>
|
||||
<h3 className={styles.title}>{intl.formatMessage(intlMessages.title)}</h3>
|
||||
</header>
|
||||
|
||||
|
@ -11,7 +11,6 @@ const stressTest = require('./stress/stress.obj');
|
||||
const userTest = require('./user/user.obj');
|
||||
const virtualizedListTest = require('./virtualizedlist/virtualizedlist.obj');
|
||||
const webcamTest = require('./webcam/webcam.obj');
|
||||
const webcamLayout = require('./webcam/webcamlayout.obj');
|
||||
const whiteboardTest = require('./whiteboard/whiteboard.obj');
|
||||
|
||||
process.setMaxListeners(Infinity);
|
||||
@ -28,7 +27,6 @@ describe('Shared Notes ', sharedNotesTest);
|
||||
describe('User', userTest);
|
||||
describe('Virtualized List', virtualizedListTest);
|
||||
describe('Webcam', webcamTest);
|
||||
describe('Webcam Layout', webcamLayout);
|
||||
describe('Whiteboard', whiteboardTest);
|
||||
if (process.env.STRESS_TEST === 'true') {
|
||||
describe('Stress', stressTest);
|
||||
|
@ -156,6 +156,7 @@ exports.stopScreenSharing = 'button[data-test="stopScreenShare"]';
|
||||
exports.presentationToolbarWrapper = '#presentationToolbarWrapper';
|
||||
exports.presentationTitle = '[class^="presentationTitle--"]';
|
||||
exports.hidePresentation = 'button[data-test="hidePresentationButton"]';
|
||||
exports.minimizePresentation = 'button[aria-label="Minimize presentation"]';
|
||||
exports.restorePresentation = 'button[data-test="restorePresentationButton"]';
|
||||
exports.nextSlide = '[data-test="nextSlide"]';
|
||||
exports.prevSlide = '[data-test="prevSlide"]';
|
||||
@ -173,6 +174,16 @@ exports.confirmManagePresentation = 'button[data-test="confirmManagePresentation
|
||||
exports.allowPresentationDownload = 'button[data-test="allowPresentationDownload"]';
|
||||
exports.disallowPresentationDownload = 'button[data-test="disallowPresentationDownload"]';
|
||||
exports.uploadPresentationFileName = 'uploadTest.png';
|
||||
exports.presentationContainer = 'div[class^="presentationContainer--"]';
|
||||
exports.externalVideoBtn = 'li[data-test="external-video"]';
|
||||
exports.externalVideoModalHeader = 'header[data-test="videoModalHeader"]';
|
||||
exports.videoModalInput = 'input[id="video-modal-input"]';
|
||||
exports.startShareVideoBtn = 'button[aria-label="Share a new video"]';
|
||||
exports.videoPlayer = 'div[data-test="videoPlayer"]';
|
||||
// YouTube frame
|
||||
exports.youtubeLink = 'https://www.youtube.com/watch?v=Hso8yLzkqj8&ab_channel=BigBlueButton';
|
||||
exports.youtubeFrame = 'iframe[title^="YouTube"]';
|
||||
exports.ytFrameTitle = 'a[class^="ytp-title-link"]';
|
||||
|
||||
// User
|
||||
exports.firstUser = '[data-test="userListItemCurrent"]';
|
||||
|
@ -202,6 +202,7 @@ class Page {
|
||||
'--window-size=1150,980',
|
||||
'--allow-file-access',
|
||||
'--lang=en-US',
|
||||
'--disable-features=IsolateOrigins,site-per-process',
|
||||
];
|
||||
return {
|
||||
headless: false,
|
||||
|
@ -574,7 +574,7 @@ class CustomParameters {
|
||||
await this.page2.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-page1-${testName}`);
|
||||
await this.page2.screenshot(`${testName}`, `01-page2-${testName}`);
|
||||
await this.page2.waitAndClick(e.hidePresentation);
|
||||
await this.page2.waitAndClick(e.minimizePresentation);
|
||||
await this.page2.screenshot(`${testName}`, `02-page2-${testName}`);
|
||||
const zoomInCase = await util.zoomIn(this.page1);
|
||||
await this.page1.screenshot(`${testName}`, `02-page1-${testName}`);
|
||||
@ -619,7 +619,7 @@ class CustomParameters {
|
||||
await this.page2.startRecording(testName);
|
||||
await this.page1.screenshot(`${testName}`, `01-page1-${testName}`);
|
||||
await this.page2.screenshot(`${testName}`, `01-page2-${testName}`);
|
||||
await this.page2.waitAndClick(e.hidePresentation);
|
||||
await this.page2.waitAndClick(e.minimizePresentation);
|
||||
await this.page2.screenshot(`${testName}`, `02-page2-${testName}`);
|
||||
const pollCase = await util.poll(this.page1, this.page2) === true;
|
||||
await this.page2.waitForSelector(e.smallToastMsg);
|
||||
|
26
bigbluebutton-tests/puppeteer/package-lock.json
generated
26
bigbluebutton-tests/puppeteer/package-lock.json
generated
@ -793,9 +793,9 @@
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
@ -866,11 +866,11 @@
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"babel-jest": {
|
||||
@ -1996,9 +1996,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz",
|
||||
"integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA=="
|
||||
"version": "1.14.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
@ -4972,9 +4972,9 @@
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
||||
},
|
||||
"tmpl": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
|
||||
"integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE="
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
|
||||
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
|
@ -6,9 +6,9 @@
|
||||
"verbose": false
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"child_process": "^1.0.2",
|
||||
"axios": "^0.21.4",
|
||||
"babel-jest": "^27.0.6",
|
||||
"child_process": "^1.0.2",
|
||||
"dotenv": "^6.0.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"jest": "^26.6.3",
|
||||
|
@ -100,9 +100,9 @@ class Polling {
|
||||
e.receivedAnswer, e.answerMessage
|
||||
);
|
||||
await this.modPage.screenshot(testName, '04-success-to-receive-answer');
|
||||
} catch (e) {
|
||||
} catch (er) {
|
||||
await this.modPage.screenshot(testName, '04-failed-to-receive-answer');
|
||||
await this.modPage.logger(e);
|
||||
await this.modPage.logger(er);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
const Page = require('../core/page');
|
||||
const e = require('../core/elements');
|
||||
const util = require('./util');
|
||||
const { ELEMENT_WAIT_LONGER_TIME, ELEMENT_WAIT_TIME } = require('../core/constants');
|
||||
const { checkElement, checkElementTextIncludes, checkElementText } = require('../core/util');
|
||||
const { ELEMENT_WAIT_LONGER_TIME } = require('../core/constants');
|
||||
const { checkElement, checkElementText } = require('../core/util');
|
||||
|
||||
class Presentation {
|
||||
constructor() {
|
||||
@ -129,6 +129,59 @@ class Presentation {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async hideAndRestorePresentation(testName) {
|
||||
try {
|
||||
await this.modPage.waitForSelector(e.whiteboard);
|
||||
await this.modPage.screenshot(testName, '01-after-close-audio-modal');
|
||||
await this.modPage.waitAndClick(e.minimizePresentation);
|
||||
const presentationWasRemoved = await this.modPage.wasRemoved(e.presentationContainer);
|
||||
await this.modPage.screenshot(testName, '02-minimize-presentation');
|
||||
|
||||
await this.modPage.waitAndClick(e.restorePresentation);
|
||||
const presentationWasRestored = await this.modPage.hasElement(e.presentationContainer);
|
||||
await this.modPage.screenshot(testName, '03-restore-presentation');
|
||||
|
||||
return presentationWasRemoved && presentationWasRestored;
|
||||
} catch (err) {
|
||||
await this.modPage.logger(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async startExternalVideo(testName) {
|
||||
try {
|
||||
await this.modPage.waitForSelector(e.whiteboard);
|
||||
await this.modPage.screenshot(testName, '01-after-close-audio-modal');
|
||||
await this.modPage.waitAndClick(e.actions);
|
||||
await this.modPage.waitAndClick(e.externalVideoBtn);
|
||||
await this.modPage.waitForSelector(e.externalVideoModalHeader);
|
||||
await this.modPage.type(e.videoModalInput, e.youtubeLink);
|
||||
await this.modPage.screenshot(testName, '02-before-start-sharing-video');
|
||||
await this.modPage.waitAndClick(e.startShareVideoBtn);
|
||||
|
||||
const modFrame = await this.getFrame(this.modPage, e.youtubeFrame);
|
||||
await this.modPage.screenshot(testName, '03-modPage-after-rendering-frame');
|
||||
const userFrame = await this.getFrame(this.userPage, e.youtubeFrame);
|
||||
await this.userPage.screenshot(testName, '03-userPage-after-rendering-frame');
|
||||
|
||||
const resp = (await modFrame.hasElement('video')) && (await userFrame.hasElement('video'));
|
||||
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.modPage.logger(err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async getFrame(page, frameSelector) {
|
||||
await page.waitForSelector(frameSelector);
|
||||
const handleFrame = await page.page.$(frameSelector);
|
||||
const contentFrame = await handleFrame.contentFrame();
|
||||
const frame = new Page(contentFrame);
|
||||
await frame.waitForSelector(e.ytFrameTitle);
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = Presentation;
|
@ -98,5 +98,50 @@ const presentationTest = () => {
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(24.62, screenshot);
|
||||
});
|
||||
|
||||
test('Hide/Restore presentation', async () => {
|
||||
const test = new Presentation();
|
||||
let response;
|
||||
let screenshot;
|
||||
try {
|
||||
const testName = 'hideAndRestorePresentation';
|
||||
await test.modPage.logger('begin of ', testName);
|
||||
await test.initModPage(testName);
|
||||
await test.modPage.startRecording(testName);
|
||||
response = await test.hideAndRestorePresentation(testName);
|
||||
await test.modPage.stopRecording();
|
||||
screenshot = await test.modPage.page.screenshot();
|
||||
await test.modPage.logger('end of ', testName);
|
||||
} catch (e) {
|
||||
await test.modPage.logger(e);
|
||||
} finally {
|
||||
await test.modPage.close();
|
||||
}
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(24.62, screenshot);
|
||||
});
|
||||
|
||||
test('Start external video', async () => {
|
||||
const test = new Presentation();
|
||||
let response;
|
||||
let screenshot;
|
||||
try {
|
||||
const testName = 'startExternalVideo';
|
||||
await test.modPage.logger('begin of ', testName);
|
||||
await test.initPages(testName);
|
||||
await test.modPage.startRecording(testName);
|
||||
response = await test.startExternalVideo(testName);
|
||||
await test.modPage.stopRecording();
|
||||
screenshot = await test.modPage.page.screenshot();
|
||||
await test.modPage.logger('end of ', testName);
|
||||
} catch (e) {
|
||||
await test.modPage.logger(e);
|
||||
} finally {
|
||||
await closePages(test.modPage, test.userPage);
|
||||
}
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(24.62, screenshot);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = exports = presentationTest;
|
||||
|
@ -6,7 +6,7 @@ usage() {
|
||||
BBB Health Check
|
||||
|
||||
OPTIONS:
|
||||
-t <test name: webcamlayout/whiteboard/webcam/virtualizedlist/user/trigger/sharednotes/screenshare/presentation/polling/notifications/customparameters/chat/breakout/audio/all>
|
||||
-t <test name: whiteboard/webcam/virtualizedlist/user/trigger/sharednotes/screenshare/presentation/polling/notifications/customparameters/chat/breakout/audio/all>
|
||||
|
||||
-u Print usage
|
||||
HERE
|
||||
|
@ -8,14 +8,12 @@ class ShareScreen extends Page {
|
||||
super();
|
||||
}
|
||||
|
||||
async test() {
|
||||
async startSharing() {
|
||||
try {
|
||||
await util.startScreenshare(this);
|
||||
await this.waitForSelector(e.screenshareConnecting);
|
||||
await this.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
const response = await this.hasElement(e.isSharingScreen, true);
|
||||
const resp = await this.hasElement(e.isSharingScreen);
|
||||
|
||||
return response === true;
|
||||
return resp === true;
|
||||
} catch (err) {
|
||||
await this.logger(err);
|
||||
return false;
|
||||
|
@ -22,7 +22,7 @@ const screenShareTest = () => {
|
||||
await test.logger('begin of ', testName);
|
||||
await test.init(true, true, testName)
|
||||
await test.startRecording(testName);
|
||||
response = await test.test();
|
||||
response = await test.startSharing();
|
||||
await test.logger('end of ', testName);
|
||||
await test.stopRecording();
|
||||
screenshot = await test.page.screenshot();
|
||||
|
@ -3,9 +3,6 @@ const { VIDEO_LOADING_WAIT_TIME } = require('../core/constants');
|
||||
|
||||
async function startScreenshare(test) {
|
||||
await test.waitAndClick(e.startScreenSharing);
|
||||
}
|
||||
|
||||
async function waitForScreenshareContainer(test) {
|
||||
await test.waitForSelector(e.screenshareConnecting);
|
||||
await test.waitForSelector(e.screenShareVideo, VIDEO_LOADING_WAIT_TIME);
|
||||
}
|
||||
@ -17,4 +14,3 @@ async function getScreenShareBreakoutContainer(test) {
|
||||
|
||||
exports.getScreenShareBreakoutContainer = getScreenShareBreakoutContainer;
|
||||
exports.startScreenshare = startScreenshare;
|
||||
exports.waitForScreenshareContainer = waitForScreenshareContainer;
|
||||
|
@ -246,9 +246,9 @@ class MultiUsers {
|
||||
);
|
||||
await this.userPage.screenshot(testName, '04-connection-network-success');
|
||||
return true;
|
||||
} catch (e) {
|
||||
} catch (er) {
|
||||
await this.userPage.screenshot(testName, '04-connection-network-failed');
|
||||
this.userPage.logger(e);
|
||||
this.userPage.logger(er);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
@ -280,8 +280,8 @@ class MultiUsers {
|
||||
await this.page1.waitAndClick(e.userListButton);
|
||||
await this.page2.waitAndClick(e.userListButton);
|
||||
await this.page2.waitAndClick(e.chatButtonKey);
|
||||
const onUserListPanel = await this.page1.wasRemoved(e.hidePresentation);
|
||||
const onChatPanel = await this.page2.wasRemoved(e.hidePresentation);
|
||||
const onUserListPanel = await this.page1.wasRemoved(e.minimizePresentation);
|
||||
const onChatPanel = await this.page2.wasRemoved(e.minimizePresentation);
|
||||
|
||||
return onUserListPanel && onChatPanel;
|
||||
} catch (err) {
|
||||
|
@ -53,7 +53,6 @@ class Status extends Page {
|
||||
async disableScreenshareFromConnectionStatus() {
|
||||
try {
|
||||
await utilScreenshare.startScreenshare(this);
|
||||
await utilScreenshare.waitForScreenshareContainer(this);
|
||||
await util.connectionStatus(this);
|
||||
await this.waitAndClickElement(e.dataSavingScreenshare);
|
||||
await this.waitAndClickElement(e.closeConnectionStatusModal);
|
||||
@ -72,7 +71,6 @@ class Status extends Page {
|
||||
await this.joinMicrophone();
|
||||
await this.shareWebcam(true, ELEMENT_WAIT_LONGER_TIME);
|
||||
await utilScreenshare.startScreenshare(this);
|
||||
await utilScreenshare.waitForScreenshareContainer(this);
|
||||
await util.connectionStatus(this);
|
||||
await sleep(5000);
|
||||
const connectionStatusItemEmpty = await this.page.evaluate(checkElementLengthEqualTo, e.connectionStatusItemEmpty, 0);
|
||||
|
@ -54,5 +54,28 @@ const webcamTest = () => {
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(7.5, screenshot);
|
||||
});
|
||||
|
||||
test('Checks webcam talking indicator', async () => {
|
||||
const test = new Share();
|
||||
let response;
|
||||
let screenshot;
|
||||
try {
|
||||
const testName = 'joinWebcamAndMicrophone';
|
||||
await test.logger('begin of ', testName);
|
||||
await test.init(true, false, testName);
|
||||
await test.startRecording(testName);
|
||||
await test.webcamLayoutStart();
|
||||
response = await test.webcamLayoutTest(testName);
|
||||
await test.logger('end of ', testName);
|
||||
await test.stopRecording();
|
||||
screenshot = await test.page.screenshot();
|
||||
} catch (err) {
|
||||
await test.logger(err);
|
||||
} finally {
|
||||
await test.close();
|
||||
}
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(10.83, screenshot);
|
||||
});
|
||||
};
|
||||
module.exports = exports = webcamTest;
|
||||
|
@ -1,36 +0,0 @@
|
||||
const Page = require('../core/page');
|
||||
const Share = require('./share');
|
||||
const { toMatchImageSnapshot } = require('jest-image-snapshot');
|
||||
const { MAX_WEBCAM_LAYOUT_TEST_TIMEOUT } = require('../core/constants');
|
||||
|
||||
expect.extend({ toMatchImageSnapshot });
|
||||
|
||||
const webcamLayoutTest = () => {
|
||||
beforeEach(() => {
|
||||
jest.setTimeout(MAX_WEBCAM_LAYOUT_TEST_TIMEOUT);
|
||||
});
|
||||
|
||||
test('Join Webcam and microphone', async () => {
|
||||
const test = new Share();
|
||||
let response;
|
||||
let screenshot;
|
||||
try {
|
||||
const testName = 'joinWebcamAndMicrophone';
|
||||
await test.logger('begin of ', testName);
|
||||
await test.init(true, false, testName);
|
||||
await test.startRecording(testName);
|
||||
await test.webcamLayoutStart();
|
||||
response = await test.webcamLayoutTest(testName);
|
||||
await test.logger('end of ', testName);
|
||||
await test.stopRecording();
|
||||
screenshot = await test.page.screenshot();
|
||||
} catch (err) {
|
||||
await test.logger(err);
|
||||
} finally {
|
||||
await test.close();
|
||||
}
|
||||
expect(response).toBe(true);
|
||||
Page.checkRegression(10.83, screenshot);
|
||||
});
|
||||
};
|
||||
module.exports = exports = webcamLayoutTest;
|
@ -1,3 +0,0 @@
|
||||
const webcamLayoutTest = require('./webcamlayout.obj');
|
||||
|
||||
describe('Webcams Layout', webcamLayoutTest);
|
@ -407,3 +407,6 @@ endWhenNoModerator=false
|
||||
|
||||
# Number of minutes to wait for moderator rejoin before end meeting (if `endWhenNoModerator` enabled)
|
||||
endWhenNoModeratorDelayInMinutes=1
|
||||
|
||||
# Allow endpoint with current BigBlueButton version
|
||||
allowRevealOfBBBVersion=false
|
||||
|
@ -186,6 +186,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<property name="endWhenNoModerator" value="${endWhenNoModerator}"/>
|
||||
<property name="endWhenNoModeratorDelayInMinutes" value="${endWhenNoModeratorDelayInMinutes}"/>
|
||||
<property name="defaultKeepEvents" value="${defaultKeepEvents}"/>
|
||||
<property name="allowRevealOfBBBVersion" value="${allowRevealOfBBBVersion}"/>
|
||||
</bean>
|
||||
|
||||
<import resource="doc-conversion.xml"/>
|
||||
|
@ -83,7 +83,7 @@ class ApiController {
|
||||
|
||||
withFormat {
|
||||
xml {
|
||||
render(text: responseBuilder.buildMeetingVersion(paramsProcessorUtil.getApiVersion(), RESP_CODE_SUCCESS), contentType: "text/xml")
|
||||
render(text: responseBuilder.buildMeetingVersion(paramsProcessorUtil.getApiVersion(), paramsProcessorUtil.getBbbVersion(), RESP_CODE_SUCCESS), contentType: "text/xml")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,6 +126,8 @@ class ApiController {
|
||||
|
||||
Meeting newMeeting = paramsProcessorUtil.processCreateParams(params)
|
||||
|
||||
ApiErrors errors = new ApiErrors()
|
||||
|
||||
if (meetingService.createMeeting(newMeeting)) {
|
||||
// See if the request came with pre-uploading of presentation.
|
||||
uploadDocuments(newMeeting); //
|
||||
@ -183,6 +185,11 @@ class ApiController {
|
||||
request.getQueryString()
|
||||
)
|
||||
|
||||
HashMap<String, String> roles = new HashMap<String, String>();
|
||||
|
||||
roles.put("moderator", ROLE_MODERATOR);
|
||||
roles.put("viewer", ROLE_ATTENDEE);
|
||||
|
||||
if(!(validationResponse == null)) {
|
||||
invalid(validationResponse.getKey(), validationResponse.getValue(), REDIRECT_RESPONSE)
|
||||
return
|
||||
@ -247,6 +254,10 @@ class ApiController {
|
||||
role = Meeting.ROLE_ATTENDEE
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(params.role) && roles.containsKey(params.role.toLowerCase())) {
|
||||
role = roles.get(params.role.toLowerCase());
|
||||
}
|
||||
|
||||
// We preprend "w_" to our internal meeting Id to indicate that this is a web user.
|
||||
// For users joining using the phone, we will prepend "v_" so it will be easier
|
||||
// to distinguish users who doesn't have a web client. (ralam june 12, 2017)
|
||||
@ -358,13 +369,10 @@ class ApiController {
|
||||
session[sessionToken] = sessionToken
|
||||
meetingService.addUserSession(sessionToken, us)
|
||||
|
||||
logSessionInfo()
|
||||
|
||||
//Identify which of these to logs should be used. sessionToken or user-token
|
||||
log.info("Session sessionToken for " + us.fullname + " [" + session[sessionToken] + "]")
|
||||
log.info("Session user-token for " + us.fullname + " [" + session['user-token'] + "]")
|
||||
|
||||
logSession()
|
||||
log.info("Session token: ${sessionToken}")
|
||||
|
||||
// Process if we send the user directly to the client or
|
||||
@ -792,8 +800,6 @@ class ApiController {
|
||||
String API_CALL = 'enter'
|
||||
log.debug CONTROLLER_NAME + "#${API_CALL}"
|
||||
|
||||
logSessionInfo()
|
||||
|
||||
String respMessage = "Session not found."
|
||||
boolean reject = false;
|
||||
|
||||
@ -835,7 +841,6 @@ class ApiController {
|
||||
logoutUrl = us.logoutUrl
|
||||
}
|
||||
|
||||
logSession()
|
||||
log.info("Session token: ${sessionToken}")
|
||||
|
||||
response.addHeader("Cache-Control", "no-cache")
|
||||
@ -1412,8 +1417,6 @@ class ApiController {
|
||||
return false
|
||||
}
|
||||
|
||||
logSession()
|
||||
|
||||
if (!session[token]) {
|
||||
log.info("Session for token ${token} not found")
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
<response>
|
||||
<#-- Where code is a 'SUCCESS' String -->
|
||||
<returncode>${returnCode}</returncode>
|
||||
<version>${version}</version>
|
||||
<apiVersion>${apiVersion}</apiVersion>
|
||||
<bbbVersion>${bbbVersion}</bbbVersion>
|
||||
</response>
|
||||
</#compress>
|
||||
|
@ -45,7 +45,7 @@ export ROOT_URL=http://127.0.0.1/html5client
|
||||
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
|
||||
export MONGO_URL=mongodb://127.0.1.1/meteor
|
||||
export NODE_ENV=production
|
||||
export NODE_VERSION=node-v14.17.6-linux-x64
|
||||
export NODE_VERSION=node-v14.18.1-linux-x64
|
||||
export SERVER_WEBSOCKET_COMPRESSION=0
|
||||
export BIND_IP=127.0.0.1
|
||||
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=$INSTANCE_ID
|
||||
|
@ -45,7 +45,7 @@ export ROOT_URL=http://127.0.0.1/html5client
|
||||
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
|
||||
export MONGO_URL=mongodb://127.0.1.1/meteor
|
||||
export NODE_ENV=production
|
||||
export NODE_VERSION=node-v14.17.6-linux-x64
|
||||
export NODE_VERSION=node-v14.18.1-linux-x64
|
||||
export SERVER_WEBSOCKET_COMPRESSION=0
|
||||
export BIND_IP=127.0.0.1
|
||||
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js
|
||||
|
@ -35,6 +35,7 @@ mkdir -p staging/usr/share/meteor
|
||||
rm -rf /tmp/html5-build
|
||||
mkdir -p /tmp/html5-build
|
||||
|
||||
npm -v
|
||||
meteor npm -v
|
||||
meteor node -v
|
||||
cat .meteor/release
|
||||
@ -42,19 +43,29 @@ cat .meteor/release
|
||||
# meteor version control was moved to the Dockerfile of the image used in .gitlab-ci.yml
|
||||
# meteor update --allow-superuser --release 2.3.6
|
||||
|
||||
# build the HTML5 client
|
||||
# Install the npm dependencies needed for the HTML5 client.
|
||||
# Argument 'c' means package-lock.json will be respected
|
||||
# --production means we won't be installing devDependencies
|
||||
meteor npm ci --production
|
||||
|
||||
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build /tmp/html5-build --architecture os.linux.x86_64 --allow-superuser
|
||||
# Build the HTML5 client https://guide.meteor.com/deployment.html#custom-deployment
|
||||
# https://docs.meteor.com/environment-variables.html#METEOR-DISABLE-OPTIMISTIC-CACHING - disable caching because we're only building once
|
||||
# --allow-superuser
|
||||
# --directory - instead of creating tar.gz and then extracting (which is the default option)
|
||||
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build /tmp/html5-build --architecture os.linux.x86_64 --allow-superuser --directory
|
||||
|
||||
# extract, install the npm dependencies, then copy to staging
|
||||
tar xfz /tmp/html5-build/bbb-html5_${VERSION}_${DISTRO}.tar.gz -C /tmp/html5-build/
|
||||
# Install the npm dependencies, then copy to staging
|
||||
cd /tmp/html5-build/bundle/programs/server/
|
||||
npm i --production
|
||||
|
||||
# Install Meteor related dependencies
|
||||
# Note that we don't use "c" argument as there is no package-lock.json here
|
||||
# only package.json. The dependencies for bbb-html5 are already installed in
|
||||
# /usr/share/meteor/bundle/programs/server/npm/node_modules/ and not in
|
||||
# /usr/share/meteor/bundle/programs/server/node_modules
|
||||
npm i
|
||||
cd -
|
||||
cp -r /tmp/html5-build/bundle staging/usr/share/meteor
|
||||
|
||||
|
||||
cp $DISTRO/systemd_start.sh staging/usr/share/meteor/bundle
|
||||
chmod +x staging/usr/share/meteor/bundle/systemd_start.sh
|
||||
|
||||
@ -81,11 +92,11 @@ cp $DISTRO/bbb-html5-frontend@.service staging/usr/lib/systemd/system
|
||||
|
||||
mkdir -p staging/usr/share
|
||||
|
||||
if [ ! -f node-v14.17.6-linux-x64.tar.gz ]; then
|
||||
wget https://nodejs.org/dist/v14.17.6/node-v14.17.6-linux-x64.tar.gz
|
||||
if [ ! -f node-v14.18.1-linux-x64.tar.gz ]; then
|
||||
wget https://nodejs.org/dist/v14.18.1/node-v14.18.1-linux-x64.tar.gz
|
||||
fi
|
||||
|
||||
cp node-v14.17.6-linux-x64.tar.gz staging/usr/share
|
||||
cp node-v14.18.1-linux-x64.tar.gz staging/usr/share
|
||||
|
||||
if [ -f staging/usr/share/meteor/bundle/programs/web.browser/head.html ]; then
|
||||
sed -i "s/VERSION/$(($BUILD))/" staging/usr/share/meteor/bundle/programs/web.browser/head.html
|
||||
|
Loading…
Reference in New Issue
Block a user