mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server: signalSent event
parent
ce204c661d
commit
e8dd9bd8f4
|
@ -21,6 +21,6 @@ public enum CDREventName {
|
||||||
|
|
||||||
sessionCreated, sessionDestroyed, participantJoined, participantLeft, webrtcConnectionCreated,
|
sessionCreated, sessionDestroyed, participantJoined, participantLeft, webrtcConnectionCreated,
|
||||||
webrtcConnectionDestroyed, recordingStarted, recordingStopped, recordingStatusChanged, filterEventDispatched,
|
webrtcConnectionDestroyed, recordingStarted, recordingStopped, recordingStatusChanged, filterEventDispatched,
|
||||||
mediaNodeStatusChanged, autoscaling
|
signalSent, mediaNodeStatusChanged, autoscaling
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* (C) Copyright 2017-2020 OpenVidu (https://openvidu.io)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.openvidu.server.cdr;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class CDREventSignal extends CDREvent {
|
||||||
|
|
||||||
|
private String from;
|
||||||
|
private String[] to;
|
||||||
|
private String type;
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
public CDREventSignal(String sessionId, String from, String[] to, String type, String data) {
|
||||||
|
super(CDREventName.signalSent, sessionId, System.currentTimeMillis());
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.type = type;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject json = super.toJson();
|
||||||
|
json.addProperty("from", this.from);
|
||||||
|
JsonArray toArray = new JsonArray();
|
||||||
|
for (String id : this.to) {
|
||||||
|
toArray.add(id);
|
||||||
|
}
|
||||||
|
json.add("to", toArray);
|
||||||
|
json.addProperty("type", this.type);
|
||||||
|
json.addProperty("data", this.data);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,52 +42,8 @@ import io.openvidu.server.summary.SessionSummary;
|
||||||
import io.openvidu.server.webhook.CDRLoggerWebhook;
|
import io.openvidu.server.webhook.CDRLoggerWebhook;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CDR logger to register all information of a Session.
|
* CDR logger to register all information of a Session. Enabled by property
|
||||||
* Enabled by property 'OPENVIDU_CDR=true'
|
* 'OPENVIDU_CDR=true'
|
||||||
*
|
|
||||||
* - 'sessionCreated': {sessionId, timestamp}
|
|
||||||
* - 'sessionDestroyed': {sessionId, timestamp, startTime, duration, reason}
|
|
||||||
* - 'participantJoined': {sessionId, timestamp, participantId, location, platform}
|
|
||||||
* - 'participantLeft': {sessionId, timestamp, participantId, startTime, duration, reason}
|
|
||||||
* - 'webrtcConnectionCreated' {sessionId, timestamp, participantId, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate]}
|
|
||||||
* - 'webrtcConnectionDestroyed' {sessionId, timestamp, participantId, startTime, duration, connection, [receivingFrom], audioEnabled, videoEnabled, [videoSource], [videoFramerate], reason}
|
|
||||||
* - 'recordingStarted' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size}
|
|
||||||
* - 'recordingStopped' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size}
|
|
||||||
* - 'recordingStatusChanged' {sessionId, timestamp, id, name, hasAudio, hasVideo, resolution, recordingLayout, size, status}
|
|
||||||
* - 'filterEventDispatched' {sessionId, timestamp, participantId, streamId, filterType, eventType, data}
|
|
||||||
*
|
|
||||||
* PROPERTIES VALUES:
|
|
||||||
*
|
|
||||||
* - sessionId: string
|
|
||||||
* - timestamp: number
|
|
||||||
* - startTime: number
|
|
||||||
* - duration: number
|
|
||||||
* - participantId: string
|
|
||||||
* - connection: "INBOUND", "OUTBOUND"
|
|
||||||
* - receivingFrom: string
|
|
||||||
* - audioEnabled: boolean
|
|
||||||
* - videoEnabled: boolean
|
|
||||||
* - videoSource: "CAMERA", "SCREEN", "CUSTOM", "IPCAM"
|
|
||||||
* - videoFramerate: number
|
|
||||||
* - videoDimensions: string
|
|
||||||
* - id: string
|
|
||||||
* - name: string
|
|
||||||
* - hasAudio: boolean
|
|
||||||
* - hasVideo: boolean
|
|
||||||
* - resolution string
|
|
||||||
* - recordingLayout: string
|
|
||||||
* - size: number
|
|
||||||
* - status: string
|
|
||||||
* - webrtcConnectionDestroyed.reason: "unsubscribe", "unpublish", "disconnect", "networkDisconnect", "mediaServerDisconnect", "openviduServerStopped"
|
|
||||||
* - participantLeft.reason: "unsubscribe", "unpublish", "disconnect", "networkDisconnect", "mediaServerDisconnect", "openviduServerStopped"
|
|
||||||
* - sessionDestroyed.reason: "lastParticipantLeft", "mediaServerDisconnect", "openviduServerStopped"
|
|
||||||
* - recordingStopped.reason: "recordingStoppedByServer", "lastParticipantLeft", "sessionClosedByServer", "automaticStop", "mediaServerDisconnect", "openviduServerStopped"
|
|
||||||
*
|
|
||||||
* [OPTIONAL_PROPERTIES]:
|
|
||||||
* - receivingFrom: only if connection = "INBOUND"
|
|
||||||
* - videoSource: only if videoEnabled = true
|
|
||||||
* - videoFramerate: only if videoEnabled = true
|
|
||||||
* - videoDimensions: only if videoEnabled = true
|
|
||||||
*
|
*
|
||||||
* @author Pablo Fuente (pablofuenteperez@gmail.com)
|
* @author Pablo Fuente (pablofuenteperez@gmail.com)
|
||||||
*/
|
*/
|
||||||
|
@ -228,6 +184,13 @@ public class CallDetailRecord {
|
||||||
this.log(new CDREventFilterEvent(sessionId, participantId, streamId, filterType, event));
|
this.log(new CDREventFilterEvent(sessionId, participantId, streamId, filterType, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void recordSignalSent(String sessionId, String from, String[] to, String type, String data) {
|
||||||
|
if (from != null) {
|
||||||
|
type = type.replaceFirst("^signal:", "");
|
||||||
|
}
|
||||||
|
this.log(new CDREventSignal(sessionId, from, to, type, data));
|
||||||
|
}
|
||||||
|
|
||||||
protected void log(CDREvent event) {
|
protected void log(CDREvent event) {
|
||||||
this.loggers.forEach(logger -> {
|
this.loggers.forEach(logger -> {
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ public class SessionEventsHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSendMessage(Participant participant, JsonObject message, Set<Participant> participants,
|
public void onSendMessage(Participant participant, JsonObject message, Set<Participant> participants,
|
||||||
Integer transactionId, OpenViduException error) {
|
String sessionId, Integer transactionId, OpenViduException error) {
|
||||||
|
|
||||||
boolean isRpcCall = transactionId != null;
|
boolean isRpcCall = transactionId != null;
|
||||||
if (isRpcCall) {
|
if (isRpcCall) {
|
||||||
|
@ -332,16 +332,22 @@ public class SessionEventsHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String from = null;
|
||||||
|
String type = null;
|
||||||
|
String data = null;
|
||||||
|
|
||||||
JsonObject params = new JsonObject();
|
JsonObject params = new JsonObject();
|
||||||
if (message.has("data")) {
|
if (message.has("data")) {
|
||||||
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, message.get("data").getAsString());
|
data = message.get("data").getAsString();
|
||||||
|
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_DATA_PARAM, data);
|
||||||
}
|
}
|
||||||
if (message.has("type")) {
|
if (message.has("type")) {
|
||||||
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, message.get("type").getAsString());
|
type = message.get("type").getAsString();
|
||||||
|
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_TYPE_PARAM, type);
|
||||||
}
|
}
|
||||||
if (participant != null) {
|
if (participant != null) {
|
||||||
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM,
|
from = participant.getParticipantPublicId();
|
||||||
participant.getParticipantPublicId());
|
params.addProperty(ProtocolElements.PARTICIPANTSENDMESSAGE_FROM_PARAM, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<String> toSet = new HashSet<String>();
|
Set<String> toSet = new HashSet<String>();
|
||||||
|
@ -360,6 +366,7 @@ public class SessionEventsHandler {
|
||||||
|
|
||||||
if (toSet.isEmpty()) {
|
if (toSet.isEmpty()) {
|
||||||
for (Participant p : participants) {
|
for (Participant p : participants) {
|
||||||
|
toSet.add(p.getParticipantPublicId());
|
||||||
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
rpcNotificationService.sendNotification(p.getParticipantPrivateId(),
|
||||||
ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD, params);
|
ProtocolElements.PARTICIPANTSENDMESSAGE_METHOD, params);
|
||||||
}
|
}
|
||||||
|
@ -382,6 +389,8 @@ public class SessionEventsHandler {
|
||||||
if (isRpcCall) {
|
if (isRpcCall) {
|
||||||
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject());
|
rpcNotificationService.sendResponse(participant.getParticipantPrivateId(), transactionId, new JsonObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDR.recordSignalSent(sessionId, from, toSet.toArray(new String[toSet.size()]), type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStreamPropertyChanged(Participant participant, Integer transactionId, Set<Participant> participants,
|
public void onStreamPropertyChanged(Participant participant, Integer transactionId, Set<Participant> participants,
|
||||||
|
|
|
@ -116,7 +116,7 @@ public abstract class SessionManager {
|
||||||
public void sendMessage(String message, String sessionId) {
|
public void sendMessage(String message, String sessionId) {
|
||||||
try {
|
try {
|
||||||
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
|
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
|
||||||
sessionEventsHandler.onSendMessage(null, messageJson, getParticipants(sessionId), null, null);
|
sessionEventsHandler.onSendMessage(null, messageJson, getParticipants(sessionId), sessionId, null, null);
|
||||||
} catch (JsonSyntaxException | IllegalStateException e) {
|
} catch (JsonSyntaxException | IllegalStateException e) {
|
||||||
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
|
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
|
||||||
"Provided signal object '" + message + "' has not a valid JSON format");
|
"Provided signal object '" + message + "' has not a valid JSON format");
|
||||||
|
@ -127,7 +127,7 @@ public abstract class SessionManager {
|
||||||
try {
|
try {
|
||||||
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
|
JsonObject messageJson = JsonParser.parseString(message).getAsJsonObject();
|
||||||
sessionEventsHandler.onSendMessage(participant, messageJson, getParticipants(participant.getSessionId()),
|
sessionEventsHandler.onSendMessage(participant, messageJson, getParticipants(participant.getSessionId()),
|
||||||
transactionId, null);
|
participant.getSessionId(), transactionId, null);
|
||||||
} catch (JsonSyntaxException | IllegalStateException e) {
|
} catch (JsonSyntaxException | IllegalStateException e) {
|
||||||
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
|
throw new OpenViduException(Code.SIGNAL_FORMAT_INVALID_ERROR_CODE,
|
||||||
"Provided signal object '" + message + "' has not a valid JSON format");
|
"Provided signal object '" + message + "' has not a valid JSON format");
|
||||||
|
|
|
@ -24,7 +24,7 @@ OPENVIDU_CDR_PATH=/opt/openvidu/cdr
|
||||||
OPENVIDU_WEBHOOK=false
|
OPENVIDU_WEBHOOK=false
|
||||||
OPENVIDU_WEBHOOK_ENDPOINT=
|
OPENVIDU_WEBHOOK_ENDPOINT=
|
||||||
OPENVIDU_WEBHOOK_HEADERS=[]
|
OPENVIDU_WEBHOOK_HEADERS=[]
|
||||||
OPENVIDU_WEBHOOK_EVENTS=["sessionCreated","sessionDestroyed","participantJoined","participantLeft","webrtcConnectionCreated","webrtcConnectionDestroyed","recordingStatusChanged","filterEventDispatched","mediaNodeStatusChanged","autoscaling"]
|
OPENVIDU_WEBHOOK_EVENTS=["sessionCreated","sessionDestroyed","participantJoined","participantLeft","webrtcConnectionCreated","webrtcConnectionDestroyed","recordingStatusChanged","filterEventDispatched","signalSent","mediaNodeStatusChanged","autoscaling"]
|
||||||
|
|
||||||
OPENVIDU_RECORDING=false
|
OPENVIDU_RECORDING=false
|
||||||
OPENVIDU_RECORDING_DEBUG=false
|
OPENVIDU_RECORDING_DEBUG=false
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
node('container') {
|
node('container') {
|
||||||
|
|
||||||
sh 'docker rm -f e2e chrome firefox opera || true'
|
sh 'docker rm -f e2e chrome firefox opera || true'
|
||||||
sh 'rm -rf /opt/openvidu/* || true'
|
sh 'rm -rf /opt/openvidu/* || true'
|
||||||
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/barcode.y4m -P /opt/openvidu'
|
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/barcode.y4m -P /opt/openvidu'
|
||||||
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/fakeaudio.wav -P /opt/openvidu'
|
sh 'wget https://github.com/OpenVidu/openvidu/raw/master/openvidu-test-e2e/docker/fakeaudio.wav -P /opt/openvidu'
|
||||||
sh 'wget --directory-prefix=/opt/openvidu/test-layouts/layout1 https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/docker/my-custom-layout/index.html'
|
sh 'wget --directory-prefix=/opt/openvidu/test-layouts/layout1 https://raw.githubusercontent.com/OpenVidu/openvidu/master/openvidu-test-e2e/docker/my-custom-layout/index.html'
|
||||||
|
|
||||||
docker.image('openvidu/openvidu-test-e2e:$DISTRO').pull()
|
docker.image('openvidu/openvidu-test-e2e:$DISTRO').pull()
|
||||||
docker.image('selenium/standalone-chrome:latest').pull()
|
docker.image('selenium/standalone-chrome:latest').pull()
|
||||||
docker.image('selenium/standalone-firefox:latest').pull()
|
docker.image('selenium/standalone-firefox:latest').pull()
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.openqa.selenium.support.ui.ExpectedCondition;
|
||||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonNull;
|
import com.google.gson.JsonNull;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
@ -3217,6 +3218,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
|
||||||
event = CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
event = CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
||||||
Assert.assertEquals("Wrong number of properties in event 'webrtcConnectionCreated'", 10 + 1,
|
Assert.assertEquals("Wrong number of properties in event 'webrtcConnectionCreated'", 10 + 1,
|
||||||
event.keySet().size());
|
event.keySet().size());
|
||||||
|
String connectionId1 = event.get("participantId").getAsString();
|
||||||
|
|
||||||
event = CustomWebhook.waitForEvent("recordingStatusChanged", 10);
|
event = CustomWebhook.waitForEvent("recordingStatusChanged", 10);
|
||||||
Assert.assertEquals("Wrong number of properties in event 'recordingStatusChanged'", 11 + 1,
|
Assert.assertEquals("Wrong number of properties in event 'recordingStatusChanged'", 11 + 1,
|
||||||
|
@ -3258,11 +3260,53 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestAppE2eTest {
|
||||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click();
|
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click();
|
||||||
|
|
||||||
CustomWebhook.waitForEvent("participantJoined", 2);
|
event = CustomWebhook.waitForEvent("participantJoined", 2);
|
||||||
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
||||||
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
||||||
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
CustomWebhook.waitForEvent("webrtcConnectionCreated", 2);
|
||||||
|
|
||||||
|
String connectionId2 = event.get("participantId").getAsString();
|
||||||
|
|
||||||
|
// signalSent from client
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
user.getDriver().findElement(By.cssSelector(("#openvidu-instance-0 .message-btn"))).click();
|
||||||
|
user.getEventManager().waitUntilEventReaches("signal:chat", 2);
|
||||||
|
event = CustomWebhook.waitForEvent("signalSent", 1);
|
||||||
|
Assert.assertEquals("Wrong number of properties in event 'signalSent'", 6 + 1, event.keySet().size());
|
||||||
|
Assert.assertEquals("Wrong sessionId in webhook event", "TestSession",
|
||||||
|
event.get("sessionId").getAsString());
|
||||||
|
Assert.assertTrue("Wrong timestamp in webhook event", event.get("timestamp").getAsLong() > timestamp);
|
||||||
|
Assert.assertEquals("Wrong from in webhook event", connectionId1, event.get("from").getAsString());
|
||||||
|
Assert.assertEquals("Wrong type in webhook event", "chat", event.get("type").getAsString());
|
||||||
|
Assert.assertTrue("Wrong data in webhook event", !event.get("data").getAsString().isEmpty());
|
||||||
|
Assert.assertEquals("Wrong event name in webhook event", "signalSent", event.get("event").getAsString());
|
||||||
|
JsonArray toArray = event.get("to").getAsJsonArray();
|
||||||
|
Assert.assertEquals("Wrong to array size", 2, toArray.size());
|
||||||
|
Assert.assertTrue("Wrong to array content in webhook event",
|
||||||
|
toArray.contains(JsonParser.parseString(connectionId1)));
|
||||||
|
Assert.assertTrue("Wrong to array content in webhook event",
|
||||||
|
toArray.contains(JsonParser.parseString(connectionId2)));
|
||||||
|
|
||||||
|
// signalSent from server
|
||||||
|
CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET);
|
||||||
|
restClient.rest(HttpMethod.POST, "/openvidu/api/signal",
|
||||||
|
"{'session':'TestSession','type':'chat','to':['" + connectionId1 + "'],'data':'SERVER_DATA'}",
|
||||||
|
HttpStatus.SC_OK);
|
||||||
|
user.getEventManager().waitUntilEventReaches("signal:chat", 3);
|
||||||
|
event = CustomWebhook.waitForEvent("signalSent", 1);
|
||||||
|
Assert.assertEquals("Wrong number of properties in event 'signalSent'", 6 + 1, event.keySet().size());
|
||||||
|
Assert.assertEquals("Wrong sessionId in webhook event", "TestSession",
|
||||||
|
event.get("sessionId").getAsString());
|
||||||
|
Assert.assertTrue("Wrong timestamp in webhook event", event.get("timestamp").getAsLong() > timestamp);
|
||||||
|
Assert.assertTrue("Wrong from in webhook event", event.get("from").isJsonNull());
|
||||||
|
Assert.assertEquals("Wrong type in webhook event", "chat", event.get("type").getAsString());
|
||||||
|
Assert.assertEquals("Wrong data in webhook event", "SERVER_DATA", event.get("data").getAsString());
|
||||||
|
Assert.assertEquals("Wrong event name in webhook event", "signalSent", event.get("event").getAsString());
|
||||||
|
toArray = event.get("to").getAsJsonArray();
|
||||||
|
Assert.assertEquals("Wrong to array size", 1, toArray.size());
|
||||||
|
Assert.assertTrue("Wrong to array content in webhook event",
|
||||||
|
toArray.contains(JsonParser.parseString(connectionId1)));
|
||||||
|
|
||||||
user.getDriver().findElement(By.id("session-api-btn-0")).click();
|
user.getDriver().findElement(By.id("session-api-btn-0")).click();
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
user.getDriver().findElement(By.id("close-session-btn")).click();
|
user.getDriver().findElement(By.id("close-session-btn")).click();
|
||||||
|
|
Loading…
Reference in New Issue