more integration tests

This commit is contained in:
anhefti 2020-06-16 13:38:24 +02:00
parent 15226ab4a2
commit 2652da80df
3 changed files with 679 additions and 2 deletions

View file

@ -1,4 +1,4 @@
Release:
Master:
.. image:: https://travis-ci.com/SafeExamBrowser/seb-server.svg?branch=master
:target: https://travis-ci.com/SafeExamBrowser/seb-server
@ -12,7 +12,7 @@ Release:
Development:
.. image:: https://travis-ci.com/SafeExamBrowser/seb-server.svg?branch=development
:target: https://travis-ci.com/SafeExamBrowser/seb-server
:target: https://github.com/SafeExamBrowser/seb-server/tree/development
.. image:: https://codecov.io/gh/SafeExamBrowser/seb-server/branch/development/graph/badge.svg
:target: https://codecov.io/gh/SafeExamBrowser/seb-server
.. image:: https://img.shields.io/github/last-commit/SafeExamBrowser/seb-server/development?logo=github

View file

@ -0,0 +1,567 @@
/*
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui.integration;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.model.session.RunningExamInfo;
public class SEBClientBot {
private static final Logger log = LoggerFactory.getLogger(SEBClientBot.class);
private static final Character COMMA = ',';
private static final Character AMPERSAND = '&';
private static final Character EQUALITY_SIGN = '=';
private static final String LIST_SEPARATOR = COMMA.toString();
private static final String FORM_URL_ENCODED_SEPARATOR = AMPERSAND.toString();
private static final String FORM_URL_ENCODED_NAME_VALUE_SEPARATOR = EQUALITY_SIGN.toString();
private static final String PARAM_INSTITUTION_ID = "institutionId";
private static final String EXAM_API_PARAM_EXAM_ID = "examId";
private static final String EXAM_API_SEB_CONNECTION_TOKEN = "SEBConnectionToken";
private static final String EXAM_API_USER_SESSION_ID = "seb_user_session_id";
private static final String EXAM_API_HANDSHAKE_ENDPOINT = "/handshake";
private static final String EXAM_API_CONFIGURATION_REQUEST_ENDPOINT = "/examconfig";
private static final String EXAM_API_PING_ENDPOINT = "/sebping";
private static final String EXAM_API_PING_TIMESTAMP = "timestamp";
private static final String EXAM_API_PING_NUMBER = "ping-number";
private static final String EXAM_API_EVENT_ENDPOINT = "/seblog";
private static final long ONE_SECOND = 1000; // milliseconds
static final long TEN_SECONDS = 10 * ONE_SECOND;
static final long ONE_MINUTE = 60 * ONE_SECOND;
@SuppressWarnings("unused")
private static final long ONE_HOUR = 60 * ONE_MINUTE;
//private final ExecutorService executorService;
private final List<String> scopes = Arrays.asList("read", "write");
private final ObjectMapper jsonMapper = new ObjectMapper();
private final Random random = new Random();
String webserviceAddress = "http://localhost:8080";
String accessTokenEndpoint = "/oauth/token";
String clientId = "test";
String sessionId = null;
String clientSecret = "test";
String apiPath = "/exam-api";
String apiVersion = "v1";
String examId = "2";
String institutionId = "1";
int numberOfConnections = 4;
long establishDelay = 0;
long pingInterval = 100;
long pingPause = 0;
long pingPauseDelay = 0;
long errorInterval = ONE_SECOND;
long warnInterval = ONE_SECOND / 2;
long runtime = ONE_SECOND * 2;
int connectionAttempts = 1;
public SEBClientBot(final ClientCredentials credentials, final String examId, final String instId)
throws Exception {
this.clientId = credentials.clientIdAsString();
this.clientSecret = credentials.secretAsString();
this.examId = examId;
this.institutionId = instId;
//this.executorService = Executors.newFixedThreadPool(this.numberOfConnections);
for (int i = 0; i < this.numberOfConnections; i++) {
final String sessionId = StringUtils.isNotBlank(this.sessionId)
? this.sessionId
: "connection_" + getRandomName();
new ConnectionBot(sessionId).run();
//this.executorService.execute(new ConnectionBot(sessionId));
}
//this.executorService.shutdown();
}
private String getRandomName() {
final StringBuilder sb = new StringBuilder(String.valueOf(this.random.nextInt(100)));
while (sb.length() < 3) {
sb.insert(0, "0");
}
return sb.toString();
}
private final class ConnectionBot implements Runnable {
private final String name;
private final OAuth2RestTemplate restTemplate;
private final String handshakeURI = SEBClientBot.this.webserviceAddress +
SEBClientBot.this.apiPath + "/" +
SEBClientBot.this.apiVersion + EXAM_API_HANDSHAKE_ENDPOINT;
private final String configurartionURI = SEBClientBot.this.webserviceAddress +
SEBClientBot.this.apiPath + "/" +
SEBClientBot.this.apiVersion + EXAM_API_CONFIGURATION_REQUEST_ENDPOINT;
private final String pingURI = SEBClientBot.this.webserviceAddress +
SEBClientBot.this.apiPath + "/" +
SEBClientBot.this.apiVersion + EXAM_API_PING_ENDPOINT;
private final String eventURI = SEBClientBot.this.webserviceAddress +
SEBClientBot.this.apiPath + "/" +
SEBClientBot.this.apiVersion + EXAM_API_EVENT_ENDPOINT;
private final HttpEntity<?> connectBody;
protected ConnectionBot(final String name) {
this.name = name;
this.restTemplate = createRestTemplate(null);
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
this.connectBody = new HttpEntity<>(PARAM_INSTITUTION_ID +
FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
SEBClientBot.this.institutionId
// + Constants.FORM_URL_ENCODED_SEPARATOR
// + API.EXAM_API_PARAM_EXAM_ID
// + Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR
// + this.examId
,
headers);
}
@Override
public void run() {
int attempt = 0;
String connectionToken = null;
while (connectionToken == null && attempt < SEBClientBot.this.connectionAttempts) {
attempt++;
log.info("ConnectionBot {} : Try to request access-token; attempt: {}", this.name, attempt);
try {
final OAuth2AccessToken accessToken = this.restTemplate.getAccessToken();
log.info("ConnectionBot {} : Got access token: {}", this.name, accessToken);
connectionToken = createConnection();
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed to request access-token: ", this.name, e);
if (attempt >= SEBClientBot.this.connectionAttempts) {
log.error("ConnectionBot {} : Gave up afer {} connection attempts: ", this.name, attempt);
throw new RuntimeException("Connection Error. See Logs", e);
}
}
}
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
headers.set(EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
final MultiValueMap<String, String> eventHeaders = new LinkedMultiValueMap<>();
eventHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
eventHeaders.set(EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
if (connectionToken != null) {
if (getConfig(headers) && establishConnection(headers)) {
final PingEntity pingHeader = new PingEntity(headers);
final EventEntity errorHeader = new EventEntity(eventHeaders, "ERROR_LOG");
final EventEntity warnHeader = new EventEntity(eventHeaders, "WARN_LOG");
try {
final long startTime = System.currentTimeMillis();
final long endTime = startTime + SEBClientBot.this.runtime;
final long pingPauseStart = startTime + SEBClientBot.this.pingPauseDelay;
final long pingPauseEnd = pingPauseStart + SEBClientBot.this.pingPause;
long currentTime = startTime;
long lastPingTime = startTime;
long lastErrorTime = startTime;
long lastWarnTime = startTime;
while (currentTime < endTime) {
if (currentTime - lastPingTime >= SEBClientBot.this.pingInterval &&
!(currentTime > pingPauseStart && currentTime < pingPauseEnd)) {
pingHeader.next();
if (!sendPing(pingHeader)) {
// expecting a quit instruction was sent here
return;
}
lastPingTime = currentTime;
}
if (currentTime - lastErrorTime >= SEBClientBot.this.errorInterval) {
errorHeader.next();
sendEvent(errorHeader);
lastErrorTime = currentTime;
}
if (currentTime - lastWarnTime >= SEBClientBot.this.warnInterval) {
warnHeader.next();
sendEvent(warnHeader);
lastWarnTime = currentTime;
}
try {
Thread.sleep(50);
} catch (final Exception e) {
}
currentTime = System.currentTimeMillis();
}
} catch (final Throwable t) {
log.error("ConnectionBot {} : Error sending events: ", this.name, t);
throw new RuntimeException("ConnectionBot {} : Error sending events: ");
} finally {
disconnect(connectionToken);
}
}
}
}
private String createConnection() {
log.info("ConnectionBot {} : init connection", this.name);
try {
final ResponseEntity<String> exchange = this.restTemplate.exchange(
this.handshakeURI,
HttpMethod.POST,
this.connectBody,
new ParameterizedTypeReference<String>() {
});
final HttpStatus statusCode = exchange.getStatusCode();
if (statusCode.isError()) {
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
}
final Collection<RunningExamInfo> body = SEBClientBot.this.jsonMapper.readValue(
exchange.getBody(),
new TypeReference<Collection<RunningExamInfo>>() {
});
final String token = exchange.getHeaders().getFirst(EXAM_API_SEB_CONNECTION_TOKEN);
log.info("ConnectionBot {} : successfully created connection, token: {} body: {} ",
this.name,
token,
body);
return token;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed to init connection", this.name, e);
throw new RuntimeException("ConnectionBot {} : Failed to init connection: ", e);
}
}
public boolean getConfig(final MultiValueMap<String, String> headers) {
final HttpEntity<?> configHeader = new HttpEntity<>(headers);
log.info("ConnectionBot {} : get SEB Configuration", this.name);
try {
final ResponseEntity<byte[]> exchange = this.restTemplate.exchange(
this.configurartionURI + "?" + EXAM_API_PARAM_EXAM_ID +
FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
SEBClientBot.this.examId,
HttpMethod.GET,
configHeader,
new ParameterizedTypeReference<byte[]>() {
});
final HttpStatus statusCode = exchange.getStatusCode();
if (statusCode.isError()) {
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
}
final byte[] config = exchange.getBody();
if (ArrayUtils.isEmpty(config)) {
log.error("No Exam config get from API. processing anyway");
}
if (log.isDebugEnabled()) {
log.debug(
"ConnectionBot {} : successfully requested exam config: " + SEBClientBot.toString(config),
this.name);
} else {
log.info("ConnectionBot {} : successfully requested exam config", this.name);
}
return true;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed get SEB Configuration", this.name, e);
return false;
}
}
public boolean establishConnection(final MultiValueMap<String, String> headers) {
if (SEBClientBot.this.establishDelay > 0) {
try {
log.info("Wait for connection activation -> {}", SEBClientBot.this.establishDelay);
Thread.sleep(SEBClientBot.this.establishDelay);
} catch (final Exception e) {
log.error("Failed to wait for connection activiation -> {} : {}",
SEBClientBot.this.establishDelay,
e.getMessage());
throw new RuntimeException();
}
}
final HttpEntity<?> configHeader = new HttpEntity<>(
EXAM_API_USER_SESSION_ID +
FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
this.name,
headers);
log.info("ConnectionBot {} : Trying to establish SEB client connection", this.name);
try {
final ResponseEntity<String> exchange = this.restTemplate.exchange(
this.handshakeURI,
HttpMethod.PUT,
configHeader,
new ParameterizedTypeReference<String>() {
});
final HttpStatus statusCode = exchange.getStatusCode();
if (statusCode.isError()) {
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
}
log.info("ConnectionBot {} : successfully established SEB client connection", this.name);
return true;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed get established SEB client connection", this.name, e);
throw new RuntimeException();
}
}
private boolean sendPing(final HttpEntity<String> pingHeader) {
try {
final ResponseEntity<String> exchange = this.restTemplate.exchange(
this.pingURI,
HttpMethod.POST,
pingHeader,
new ParameterizedTypeReference<String>() {
});
if (exchange.hasBody() && exchange.getBody().contains("SEB_QUIT")) {
log.info("SEB_QUIT client {}, response: {}",
pingHeader.getHeaders().get(EXAM_API_SEB_CONNECTION_TOKEN),
exchange.getBody());
return false;
}
return true;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed send ping", this.name, e);
throw new RuntimeException();
}
}
private boolean sendEvent(final HttpEntity<String> eventHeader) {
try {
this.restTemplate.exchange(
this.eventURI,
HttpMethod.POST,
eventHeader,
new ParameterizedTypeReference<String>() {
});
return true;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed send event", this.name, e);
throw new RuntimeException();
}
}
public boolean disconnect(final String connectionToken) {
final MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
headers.set(EXAM_API_SEB_CONNECTION_TOKEN, connectionToken);
final HttpEntity<?> configHeader = new HttpEntity<>(headers);
log.info("ConnectionBot {} : Trying to delete SEB client connection", this.name);
try {
final ResponseEntity<String> exchange = this.restTemplate.exchange(
this.handshakeURI,
HttpMethod.DELETE,
configHeader,
new ParameterizedTypeReference<String>() {
});
final HttpStatus statusCode = exchange.getStatusCode();
if (statusCode.isError()) {
throw new RuntimeException("Webservice answered with error: " + exchange.getBody());
}
log.info("ConnectionBot {} : successfully deleted SEB client connection", this.name);
return true;
} catch (final Exception e) {
log.error("ConnectionBot {} : Failed get deleted SEB client connection", this.name, e);
throw new RuntimeException();
}
}
}
private OAuth2RestTemplate createRestTemplate(final String scopes) {
final ClientCredentialsResourceDetails clientCredentialsResourceDetails =
new ClientCredentialsResourceDetails();
clientCredentialsResourceDetails
.setAccessTokenUri(this.webserviceAddress + this.accessTokenEndpoint);
clientCredentialsResourceDetails.setClientId(this.clientId);
clientCredentialsResourceDetails.setClientSecret(this.clientSecret);
if (StringUtils.isBlank(scopes)) {
clientCredentialsResourceDetails.setScope(this.scopes);
} else {
clientCredentialsResourceDetails.setScope(
Arrays.asList(StringUtils.split(scopes, LIST_SEPARATOR)));
}
final OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientCredentialsResourceDetails);
restTemplate.setErrorHandler(new OAuth2ErrorHandler(clientCredentialsResourceDetails) {
@Override
public void handleError(final ClientHttpResponse response) throws IOException {
System.out.println("********************** handleError: " + response.getStatusCode());
super.handleError(response);
}
});
restTemplate
.getMessageConverters()
.add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
//restTemplate.setRetryBadAccessTokens(true);
final SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
simpleClientHttpRequestFactory.setReadTimeout(30000);
simpleClientHttpRequestFactory.setOutputStreaming(false);
restTemplate.setRequestFactory(simpleClientHttpRequestFactory);
return restTemplate;
}
private static class PingEntity extends HttpEntity<String> {
private final String pingBodyTemplate = EXAM_API_PING_TIMESTAMP +
FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
"%s" +
FORM_URL_ENCODED_SEPARATOR +
EXAM_API_PING_NUMBER +
FORM_URL_ENCODED_NAME_VALUE_SEPARATOR +
"%s";
private long timestamp = 0;
private int count = 0;
protected PingEntity(final MultiValueMap<String, String> headers) {
super(headers);
}
void next() {
this.timestamp = System.currentTimeMillis();
this.count++;
}
@Override
public String getBody() {
return String.format(this.pingBodyTemplate, this.timestamp, this.count);
}
@Override
public boolean hasBody() {
return true;
}
}
private static class EventEntity extends HttpEntity<String> {
private final String eventBodyTemplate =
"{ \"type\": \"%s\", \"timestamp\": %s, \"text\": \"some error " + UUID.randomUUID() + " \" }";
private long timestamp = 0;
private final String eventType;
protected EventEntity(final MultiValueMap<String, String> headers, final String eventType) {
super(headers);
this.eventType = eventType;
}
void next() {
this.timestamp = System.currentTimeMillis();
}
@Override
public String getBody() {
return String.format(this.eventBodyTemplate, this.eventType, this.timestamp);
}
@Override
public boolean hasBody() {
return true;
}
}
public static CharBuffer toCharBuffer(final ByteBuffer byteBuffer) {
if (byteBuffer == null) {
return CharBuffer.allocate(0);
}
byteBuffer.rewind();
return StandardCharsets.UTF_8.decode(byteBuffer);
}
public static String toString(final ByteBuffer byteBuffer) {
return toCharBuffer(byteBuffer).toString();
}
public static String toString(final byte[] byteArray) {
if (byteArray == null) {
return null;
}
return toString(ByteBuffer.wrap(byteArray));
}
}

View file

@ -33,6 +33,7 @@ import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.jdbc.Sql;
@ -42,6 +43,7 @@ import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
@ -73,6 +75,9 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent;
import ch.ethz.seb.sebserver.gbl.model.session.IndicatorValue;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
@ -108,6 +113,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSe
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.NewLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.SaveLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.ImportAsExam;
@ -149,12 +155,15 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.Sa
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigTableValues;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigValue;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionDataList;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetRunningExamPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ActivateUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.ChangePassword;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UseCasesIntegrationTest extends GuiIntegrationTest {
@ -2017,4 +2026,105 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
// xmlString);
}
@Autowired
private SEBClientConfigDAO sebClientConfigDAO;
@Test
@Order(17)
// *************************************
// Use Case 16: Login as examSupport2 and get running exam with data
// - Get list of running exams
// - Simulate a SEB connection
// - Join running exam by get the data for all SEB connections and for a single SEB connection.
public void testUsecase17_RunningExam() throws IOException {
final RestServiceImpl restService = createRestServiceForUser(
"examSupport2",
"examSupport2",
new GetRunningExamPage(),
new GetClientConnectionDataList(),
new GetExtendedClientEventPage());
final RestServiceImpl adminRestService = createRestServiceForUser(
"TestInstAdmin",
"987654321",
new NewClientConfig(),
new ActivateClientConfig(),
new GetClientConfigPage());
// get running exams
final Result<Page<Exam>> runningExamsCall = restService.getBuilder(GetRunningExamPage.class)
.call();
assertNotNull(runningExamsCall);
assertFalse(runningExamsCall.hasError());
final Page<Exam> page = runningExamsCall.get();
assertFalse(page.content.isEmpty());
final Exam exam = page.content.get(0);
assertEquals("Demo Quiz 1 (MOCKUP)", exam.name);
// get SEB connections
Result<Collection<ClientConnectionData>> connectionsCall =
restService.getBuilder(GetClientConnectionDataList.class)
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call();
assertNotNull(connectionsCall);
assertFalse(connectionsCall.hasError());
Collection<ClientConnectionData> connections = connectionsCall.get();
// no SEB connections available yet
assertTrue(connections.isEmpty());
// get active client config's credentials
final Result<Page<SEBClientConfig>> cconfigs = adminRestService.getBuilder(GetClientConfigPage.class)
.call();
assertNotNull(cconfigs);
assertFalse(cconfigs.hasError());
final Page<SEBClientConfig> ccPage = cconfigs.get();
assertFalse(ccPage.content.isEmpty());
final SEBClientConfig clientConfig = ccPage.content.get(0);
assertTrue(clientConfig.isActive());
final ClientCredentials credentials = this.sebClientConfigDAO.getSEBClientCredentials(clientConfig.getModelId())
.getOrThrow();
adminRestService.getBuilder(ActivateClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, clientConfig.getModelId())
.call();
// simulate a SEB connection
try {
new SEBClientBot(credentials, exam.getModelId(), String.valueOf(exam.institutionId));
Thread.sleep(2000);
} catch (final Exception e) {
fail(e.getCause().getMessage());
}
connectionsCall =
restService.getBuilder(GetClientConnectionDataList.class)
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call();
assertNotNull(connectionsCall);
assertFalse(connectionsCall.hasError());
connections = connectionsCall.get();
assertFalse(connections.isEmpty());
final ClientConnectionData conData = connections.iterator().next();
assertNotNull(conData);
assertEquals(exam.id, conData.clientConnection.examId);
assertFalse(conData.indicatorValues.isEmpty());
final IndicatorValue indicatorValue = conData.indicatorValues.get(0);
assertEquals("LAST_PING", indicatorValue.getType().name);
// get client logs
final Result<Page<ExtendedClientEvent>> clientLogPage = restService.getBuilder(GetExtendedClientEventPage.class)
.call();
assertNotNull(clientLogPage);
assertFalse(clientLogPage.hasError());
final Page<ExtendedClientEvent> clientLogs = clientLogPage.get();
assertFalse(clientLogs.isEmpty());
final ExtendedClientEvent extendedClientEvent = clientLogs.content.get(0);
assertNotNull(extendedClientEvent);
}
}