Merge remote-tracking branch 'origin/dev-1.4' into development

This commit is contained in:
anhefti 2022-07-07 16:37:22 +02:00
commit e6280ed581
14 changed files with 857 additions and 54 deletions

View file

@ -1,7 +1,7 @@
coverage:
precision: 2
round: down
range: "40...100"
range: "30..70"
status:
project:
default:

View file

@ -248,6 +248,9 @@ public final class Utils {
}
public static String formatDate(final DateTime dateTime) {
if (dateTime == null) {
return Constants.EMPTY_NOTE;
}
return dateTime.toString(Constants.STANDARD_DATE_TIME_MILLIS_FORMATTER);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2022 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.service.remote.webservice.api.batch;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetBatchActionPage extends RestCall<Page<BatchAction>> {
public GetBatchActionPage() {
super(new TypeKey<>(
CallType.GET_PAGE,
EntityType.BATCH_ACTION,
new TypeReference<Page<BatchAction>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.BATCH_ACTION_ENDPOINT);
}
}

View file

@ -156,7 +156,7 @@ public class FilterMap extends POSTMapper {
}
public String getConfigAttributeType() {
return getSQLWildcard(ConfigurationAttribute.FILTER_ATTR_TYPE);
return getString(ConfigurationAttribute.FILTER_ATTR_TYPE);
}
public Long getConfigValueConfigId() {

View file

@ -177,7 +177,7 @@ public class ConfigurationAttributeDAOImpl implements ConfigurationAttributeDAO
final ConfigurationAttributeRecord newRecord = new ConfigurationAttributeRecord(
data.id,
data.name,
data.type.name(),
data.type != null ? data.type.name() : null,
data.parentId,
data.resources,
data.validator,

View file

@ -154,11 +154,18 @@ public class DistributedIndicatorValueService implements DisposableBean {
final Long recId = this.clientIndicatorValueMapper.indicatorRecordIdByConnectionId(
connectionId,
type);
if (recId != null) {
log.debug("Distributed indicator value cache already exists for: {}, {}", connectionId, type);
if (log.isTraceEnabled()) {
log.trace("Distributed indicator value cache already exists for: {}, {}", connectionId, type);
}
return recId;
}
if (log.isDebugEnabled()) {
log.info("Missing distributed indicator value cache. Create for: {}, {}", connectionId, type);
}
// if not, create new one and return PK
final ClientIndicatorRecord clientEventRecord = new ClientIndicatorRecord(
null, connectionId, type.id, initValue);

View file

@ -60,6 +60,7 @@ import ch.ethz.seb.sebserver.gbl.util.Cryptor;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringService;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
@ -107,19 +108,22 @@ public class JitsiProctoringService implements ExamProctoringService {
private final Cryptor cryptor;
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
private final JSONMapper jsonMapper;
private final WebserviceInfo webserviceInfo;
protected JitsiProctoringService(
final AuthorizationService authorizationService,
final ExamSessionService examSessionService,
final Cryptor cryptor,
final ClientHttpRequestFactoryService clientHttpRequestFactoryService,
final JSONMapper jsonMapper) {
final JSONMapper jsonMapper,
final WebserviceInfo webserviceInfo) {
this.authorizationService = authorizationService;
this.examSessionService = examSessionService;
this.cryptor = cryptor;
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
this.jsonMapper = jsonMapper;
this.webserviceInfo = webserviceInfo;
}
@Override
@ -141,6 +145,11 @@ public class JitsiProctoringService implements ExamProctoringService {
"proctoringSettings:serverURL:invalidURL");
}
// In testing we do not check the JITSI service on URL to be able to test without service
if (this.webserviceInfo != null && this.webserviceInfo.hasProfile("test")) {
return true;
}
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory()
.getOrThrow();

View file

@ -206,19 +206,6 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
return page;
}
protected void populateFilterMap(final FilterMap filterMap, final Long institutionId, final String sort) {
// If current user has no read access for specified entity type within other institution
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
}
// If sorting is on institution name we need to join the institution table
if (sort != null && sort.contains(Entity.FILTER_ATTR_INSTITUTION)) {
filterMap.putIfAbsent(FilterMap.ATTR_ADD_INSITUTION_JOIN, Constants.TRUE_STRING);
}
}
// ******************
// * GET (names)
// ******************
@ -581,6 +568,19 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
.getOrThrow();
}
protected void populateFilterMap(final FilterMap filterMap, final Long institutionId, final String sort) {
// If current user has no read access for specified entity type within other institution
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
if (!this.authorization.hasGrant(PrivilegeType.READ, getGrantEntityType())) {
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
}
// If sorting is on institution name we need to join the institution table
if (sort != null && sort.contains(Entity.FILTER_ATTR_INSTITUTION)) {
filterMap.putIfAbsent(FilterMap.ATTR_ADD_INSITUTION_JOIN, Constants.TRUE_STRING);
}
}
protected EnumSet<EntityType> convertToEntityType(final boolean addIncludes, final List<String> includes) {
final EnumSet<EntityType> includeDependencies = (includes != null)
? (includes.isEmpty())
@ -783,24 +783,6 @@ public abstract class EntityController<T extends Entity, M extends Entity> {
return this.userActivityLogDAO.logModify(entity);
}
/** Makes a DELETE user activity log for the specified entity.
* This may be overwritten if the create user activity log should be skipped.
*
* @param entity the Entity instance
* @return Result refer to the logged Entity instance or to an error if happened */
protected String logDelete(final String modelId) {
try {
return this.entityDAO
.byModelId(modelId)
.flatMap(this::logDelete)
.map(Entity::getModelId)
.getOrThrow();
} catch (final Exception e) {
log.warn("Failed to log delete for entity id: {}", modelId, e);
return modelId;
}
}
/** Makes a DELETE user activity log for the specified entity.
* This may be overwritten if the create user activity log should be skipped.
*

View file

@ -41,7 +41,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.WebserviceInfoDAO;
@RunWith(SpringRunner.class)
@SpringBootTest(
properties = "file.encoding=UTF-8",
properties = { "file.encoding=UTF-8" },
classes = SEBServer.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
@ -62,15 +62,15 @@ public abstract class GuiIntegrationTest {
@Autowired
protected FilterChainProxy springSecurityFilterChain;
@Autowired
private WebserviceInfoDAO webserviceInfoDAO;
protected WebserviceInfoDAO webserviceInfoDAO;
@Autowired
private WebserviceInfo webserviceInfo;
protected WebserviceInfo webserviceInfo;
protected MockMvc mockMvc;
@Before
public void setup() {
this.webserviceInfoDAO.unregister(this.webserviceInfo.getWebserviceUUID());
//this.webserviceInfoDAO.unregister(this.webserviceInfo.getWebserviceUUID());
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(this.springSecurityFilterChain).build();

View file

@ -96,10 +96,15 @@ public class SEBClientBot {
long errorInterval = ONE_SECOND;
long warnInterval = ONE_SECOND / 2;
long notificationInterval = 800;
long runtime = ONE_SECOND * 3;
long runtime = ONE_SECOND * 5;
int connectionAttempts = 1;
public SEBClientBot(final String clientId, final String clientSecret, final String examId, final String instId)
public SEBClientBot(
final String clientId,
final String clientSecret,
final String examId,
final String instId,
final boolean wait)
throws Exception {
this.clientId = clientId;
@ -114,7 +119,13 @@ public class SEBClientBot {
? this.sessionId
: "connection_" + getRandomName();
new ConnectionBot(sessionId).run();
if (wait) {
new ConnectionBot(sessionId).run();
} else {
new Thread(new ConnectionBot(sessionId)).start();
}
//new ConnectionBot(sessionId).run();
//this.executorService.execute(new ConnectionBot(sessionId));
}

View file

@ -40,6 +40,7 @@ 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.http.HttpStatus;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@ -47,12 +48,15 @@ import org.springframework.util.StreamUtils;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.API.BatchActionType;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.client.ClientCredentials;
import ch.ethz.seb.sebserver.gbl.model.BatchAction;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.BATCH_ACTION;
import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION;
import ch.ethz.seb.sebserver.gbl.model.EntityDependency;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
@ -62,6 +66,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport.ErrorEntry;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.exam.Chapters;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamTemplate;
@ -69,6 +74,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.Threshold;
import ch.ethz.seb.sebserver.gbl.model.exam.IndicatorTemplate;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringFeature;
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType;
@ -97,6 +103,7 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.View;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.ExportType;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction.InstructionType;
import ch.ethz.seb.sebserver.gbl.model.session.ClientNotification;
@ -104,6 +111,7 @@ 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.session.MonitoringFullPageData;
import ch.ethz.seb.sebserver.gbl.model.session.MonitoringSEBConnectionData;
import ch.ethz.seb.sebserver.gbl.model.session.RemoteProctoringRoom;
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;
@ -114,7 +122,11 @@ import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping;
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ExamConfigurationServiceImpl;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestServiceImpl;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.DoBatchAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.GetBatchAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.batch.GetBatchActionPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ActivateSEBRestriction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.ArchiveExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamConsistency;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckExamImported;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.CheckSEBRestriction;
@ -165,7 +177,9 @@ 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.DeleteAllClientEvents;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.DeleteAllUserLogs;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.ExportSEBClientLogs;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetExtendedClientEventPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.logs.GetUserLogPage;
@ -214,18 +228,27 @@ 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.CloseProctoringRoom;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.ConfirmPendingClientNotification;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.DisableClientConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionDataList;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetClientConnectionPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetCollectingRoomConnections;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetCollectingRooms;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamClientConnectionPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetFinishedExamPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetMonitoringFullPageData;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetPendingClientNotifications;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetProctorRoomConnection;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetRunningExamPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.GetTownhallRoom;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.IsTownhallRoomAvailable;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.NotifyProctoringRoomOpened;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.OpenTownhallRoom;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.PropagateInstruction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.session.SendProctoringReconfigurationAttributes;
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.DeleteUserAccount;
@ -235,7 +258,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUs
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.NewUserAccount;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.RegisterNewUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.SaveUserAccount;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamProctoringRoomService;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UseCasesIntegrationTest extends GuiIntegrationTest {
@ -2107,6 +2132,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
new GetClientConnection(),
new GetMonitoringFullPageData(),
new GetExtendedClientEventPage(),
new ExportSEBClientLogs(),
new DeleteAllClientEvents(),
new DisableClientConnection(),
new PropagateInstruction(),
new GetClientConnectionPage(),
@ -2123,7 +2150,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
new ActivateClientConfig(),
new GetClientConfigPage(),
new GetIndicatorPage(),
new GetIndicators());
new GetIndicators(),
new DeleteAllClientEvents());
// get running exams
final Result<Page<Exam>> runningExamsCall = restService.getBuilder(GetRunningExamPage.class)
@ -2162,7 +2190,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.collect(Collectors.toList()).toString());
// get active client config's credentials
final Result<Page<SEBClientConfig>> cconfigs = adminRestService.getBuilder(GetClientConfigPage.class)
final Result<Page<SEBClientConfig>> cconfigs = adminRestService
.getBuilder(GetClientConfigPage.class)
.call();
assertNotNull(cconfigs);
assertFalse(cconfigs.hasError());
@ -2171,7 +2200,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
final SEBClientConfig clientConfig = ccPage.content.get(0);
assertTrue(clientConfig.isActive());
final ClientCredentials credentials = this.sebClientConfigDAO.getSEBClientCredentials(clientConfig.getModelId())
final ClientCredentials credentials = this.sebClientConfigDAO
.getSEBClientCredentials(clientConfig.getModelId())
.getOrThrow();
adminRestService.getBuilder(ActivateClientConfig.class)
@ -2184,8 +2214,9 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
credentials.clientIdAsString(),
this.cryptor.decrypt(credentials.secret).getOrThrow().toString(),
exam.getModelId(),
String.valueOf(exam.institutionId));
Thread.sleep(1000);
String.valueOf(exam.institutionId),
true);
//Thread.sleep(1000);
// send get connections
connectionsCall =
@ -2263,7 +2294,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
assertNotNull(instructionCall);
assertFalse(instructionCall.hasError());
Thread.sleep(1000);
//Thread.sleep(1000);
} catch (final Exception e) {
fail(e.getMessage());
}
@ -2315,7 +2346,8 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
assertEquals("DISABLED", conData.clientConnection.status.name());
// get client logs
final Result<Page<ExtendedClientEvent>> clientLogPage = restService.getBuilder(GetExtendedClientEventPage.class)
final Result<Page<ExtendedClientEvent>> clientLogPage = restService
.getBuilder(GetExtendedClientEventPage.class)
.call();
assertNotNull(clientLogPage);
@ -2325,6 +2357,32 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
final ExtendedClientEvent extendedClientEvent = clientLogs.content.get(0);
assertNotNull(extendedClientEvent);
// export client logs
restService
.getBuilder(ExportSEBClientLogs.class)
.withQueryParam(API.SEB_CLIENT_EVENT_EXPORT_TYPE, ExportType.CSV.name())
.withQueryParam(API.SEB_CLIENT_EVENT_EXPORT_INCLUDE_EXAMS, "true")
.withResponseExtractor(response -> {
final HttpStatus statusCode = response.getStatusCode();
assertEquals("200 OK", statusCode.toString());
final String csvExport = IOUtils.toString(response.getBody());
assertTrue(StringUtils.isNotBlank(csvExport));
return true;
})
.call();
// delete client logs
final Result<EntityProcessingReport> report = adminRestService
.getBuilder(DeleteAllClientEvents.class)
.withFormParam(
API.PARAM_MODEL_ID_LIST,
StringUtils.join(
clientLogs.content.stream().map(e -> e.getModelId()).collect(Collectors.toList()), ","))
.call();
assertNotNull(report);
assertFalse(report.hasError());
// get client connection page
Result<Page<ClientConnection>> connectionPageRes = restService
.getBuilder(GetClientConnectionPage.class)
@ -2344,6 +2402,44 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
connectionPage = connectionPageRes.get();
assertNotNull(connectionPage);
assertTrue(connectionPage.isEmpty());
Result<Page<ClientConnectionData>> connectionDatacall = restService
.getBuilder(GetFinishedExamClientConnectionPage.class)
.withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId())
.call();
assertNotNull(connectionDatacall);
assertFalse(connectionDatacall.hasError());
Page<ClientConnectionData> ccDataPage = connectionDatacall.get();
assertNotNull(ccDataPage);
assertFalse(ccDataPage.content.isEmpty());
final ClientConnectionData clientConnectionData = ccDataPage.content.get(0);
assertNotNull(clientConnectionData);
assertEquals("DISABLED", clientConnectionData.clientConnection.status.toString());
connectionDatacall = restService
.getBuilder(GetFinishedExamClientConnectionPage.class)
.withURIVariable(API.PARAM_PARENT_MODEL_ID, exam.getModelId())
.withQueryParam(ClientConnection.FILTER_ATTR_INFO, "test")
.call();
assertNotNull(connectionDatacall);
assertFalse(connectionDatacall.hasError());
ccDataPage = connectionDatacall.get();
assertNotNull(ccDataPage);
assertTrue(ccDataPage.content.isEmpty());
final Result<ClientConnectionData> ccDataCall = restService
.getBuilder(GetFinishedExamClientConnection.class)
.withURIVariable(API.PARAM_MODEL_ID, clientConnectionData.getModelId())
.call();
assertNotNull(ccDataCall);
assertFalse(ccDataCall.hasError());
final ClientConnectionData clientConnectionData2 = ccDataCall.get();
assertNotNull(clientConnectionData2);
assertEquals(
clientConnectionData2.clientConnection.connectionToken,
clientConnectionData.clientConnection.connectionToken);
}
@Test
@ -3457,4 +3553,466 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
}
@Test
@Order(27)
// *************************************
// Use Case 27: Login as admin and set exam proctoring settings for Jtisi
// - Get Exam (running)
// - Set Proctoring settings for exam
// - Check settings for exam
public void testUsecase27_SetProctoringSettingsJitsiForExam() throws IOException {
final RestServiceImpl restService = createRestServiceForUser(
"admin",
"admin",
new GetExamPage(),
new GetExamProctoringSettings(),
new SaveExamProctoringSettings(),
new IsTownhallRoomAvailable(),
new GetCollectingRooms());
// get exam
final Result<Page<Exam>> exams = restService
.getBuilder(GetExamPage.class)
.call();
assertNotNull(exams);
assertFalse(exams.hasError());
final Page<Exam> examPage = exams.get();
assertFalse(examPage.isEmpty());
final Exam runningExam = examPage.content
.stream()
.filter(exam -> exam.status == ExamStatus.RUNNING)
.findFirst()
.orElse(null);
assertNotNull(runningExam);
assertTrue(runningExam.status == ExamStatus.RUNNING);
final Result<ProctoringServiceSettings> pSettings = restService
.getBuilder(GetExamProctoringSettings.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call();
assertNotNull(pSettings);
assertFalse(pSettings.hasError());
ProctoringServiceSettings proctoringServiceSettings = pSettings.get();
assertFalse(proctoringServiceSettings.enableProctoring);
assertNull(proctoringServiceSettings.serverURL);
// set proctoring settings
final ProctoringServiceSettings newProctoringServiceSettings = new ProctoringServiceSettings(
runningExam.id,
true,
ProctoringServerType.JITSI_MEET,
"https://test.proc/service",
2,
EnumSet.allOf(ProctoringFeature.class),
true,
"appKey", "appSecret",
"sdkKey", "sdkSecret",
false);
final Result<ProctoringServiceSettings> newProcSettings = restService
.getBuilder(SaveExamProctoringSettings.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withBody(newProctoringServiceSettings)
.call();
assertNotNull(newProcSettings);
assertFalse(newProcSettings.hasError());
proctoringServiceSettings = restService
.getBuilder(GetExamProctoringSettings.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertTrue(proctoringServiceSettings.enableProctoring);
assertEquals("https://test.proc/service", proctoringServiceSettings.serverURL);
final String twonhallRoom = restService
.getBuilder(IsTownhallRoomAvailable.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertEquals("true", twonhallRoom);
final Collection<RemoteProctoringRoom> collectingRooms = restService
.getBuilder(GetCollectingRooms.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertNotNull(collectingRooms);
assertTrue(collectingRooms.isEmpty());
}
@Autowired
private ExamProctoringRoomService examProcotringRoomService;
@Autowired
private ClientConnectionDAO clientConnectionDAO;
@Test
@Order(28)
// *************************************
// Use Case 28: Login as admin and connect with SEBs to running exam with procotring enabled
// - Get Exam (running)
// - start some SEB clients connecting to running exam
// - Check collecting rooms created
public void testUsecase28_TestExamProctoring() throws IOException {
final RestServiceImpl restService = createRestServiceForUser(
"admin",
"admin",
new GetExamPage(),
new GetExamProctoringSettings(),
new SaveExamProctoringSettings(),
new IsTownhallRoomAvailable(),
new GetCollectingRooms(),
new GetClientConfigPage(),
new ActivateClientConfig(),
new NewClientConfig(),
new GetClientConfig(),
new GetProctorRoomConnection(),
new GetCollectingRoomConnections(),
new NotifyProctoringRoomOpened(),
new SendProctoringReconfigurationAttributes(),
new GetTownhallRoom(),
new OpenTownhallRoom(),
new CloseProctoringRoom());
// get exam
final Result<Page<Exam>> exams = restService
.getBuilder(GetExamPage.class)
.call();
assertNotNull(exams);
assertFalse(exams.hasError());
final Page<Exam> examPage = exams.get();
assertFalse(examPage.isEmpty());
final Exam runningExam = examPage.content
.stream()
.filter(exam -> exam.status == ExamStatus.RUNNING)
.findFirst()
.orElse(null);
assertNotNull(runningExam);
assertTrue(runningExam.status == ExamStatus.RUNNING);
final Result<ProctoringServiceSettings> pSettings = restService
.getBuilder(GetExamProctoringSettings.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call();
assertNotNull(pSettings);
assertFalse(pSettings.hasError());
final ProctoringServiceSettings proctoringServiceSettings = pSettings.get();
assertTrue(proctoringServiceSettings.enableProctoring);
assertEquals("https://test.proc/service", proctoringServiceSettings.serverURL);
// start some SEB connections for this exam
// create SEB Client Config without password protection
Result<SEBClientConfig> newConfigResponse = restService
.getBuilder(NewClientConfig.class)
.withFormParam(Domain.SEB_CLIENT_CONFIGURATION.ATTR_NAME, "No Password Protection")
.withFormParam(SEBClientConfig.ATTR_FALLBACK, Constants.TRUE_STRING)
.withFormParam(SEBClientConfig.ATTR_FALLBACK_START_URL, "http://fallback.com/fallback")
.withFormParam(SEBClientConfig.ATTR_FALLBACK_TIMEOUT, "100")
.withFormParam(SEBClientConfig.ATTR_FALLBACK_ATTEMPTS, "5")
.withFormParam(SEBClientConfig.ATTR_FALLBACK_ATTEMPT_INTERVAL, "5")
.withFormParam(SEBClientConfig.ATTR_CONFIG_PURPOSE, SEBClientConfig.ConfigPurpose.START_EXAM.name())
.call();
assertNotNull(newConfigResponse);
assertFalse(newConfigResponse.hasError());
final SEBClientConfig sebClientConfig = newConfigResponse.get();
assertEquals("No Password Protection", sebClientConfig.name);
assertFalse(sebClientConfig.isActive());
assertEquals("http://fallback.com/fallback", sebClientConfig.fallbackStartURL);
// activate the new Client Configuration
restService
.getBuilder(ActivateClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId())
.call();
newConfigResponse = restService.getBuilder(GetClientConfig.class)
.withURIVariable(API.PARAM_MODEL_ID, sebClientConfig.getModelId())
.call();
final SEBClientConfig clientConfig = newConfigResponse.get();
assertTrue(clientConfig.isActive());
final ClientCredentials credentials = this.sebClientConfigDAO
.getSEBClientCredentials(clientConfig.getModelId())
.getOrThrow();
assertTrue(clientConfig.isActive());
// simulate a SEB connection
try {
new SEBClientBot(
credentials.clientIdAsString(),
this.cryptor.decrypt(credentials.secret).getOrThrow().toString(),
runningExam.getModelId(),
String.valueOf(runningExam.institutionId),
false);
Thread.sleep(1000);
this.examProcotringRoomService.updateProctoringCollectingRooms();
// check collecting room was created
final Collection<RemoteProctoringRoom> collectingRooms = restService
.getBuilder(GetCollectingRooms.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertNotNull(collectingRooms);
assertFalse(collectingRooms.isEmpty());
// Two rooms a two people for four connections
assertEquals(2, collectingRooms.size());
final RemoteProctoringRoom room1 = collectingRooms.iterator().next();
assertEquals(2, room1.roomSize.intValue());
assertFalse(room1.townhallRoom);
final ProctoringRoomConnection proctoringRoomConnection = restService
.getBuilder(GetProctorRoomConnection.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, room1.name)
.call()
.get();
assertNotNull(proctoringRoomConnection);
assertEquals(room1.name, proctoringRoomConnection.roomName);
assertNotNull(proctoringRoomConnection.accessToken);
// notify room open
restService
.getBuilder(NotifyProctoringRoomOpened.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, room1.name)
.call()
.get();
// reconfigure clients in room
restService
.getBuilder(SendProctoringReconfigurationAttributes.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withQueryParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, room1.name)
.withQueryParam(API.EXAM_PROCTORING_ATTR_RECEIVE_AUDIO, "true")
.withQueryParam(API.EXAM_PROCTORING_ATTR_RECEIVE_VIDEO, "true")
.withQueryParam(API.EXAM_PROCTORING_ATTR_ALLOW_CHAT, "true")
.call()
.get();
final Collection<ClientConnection> collection = restService
.getBuilder(GetCollectingRoomConnections.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withQueryParam(Domain.REMOTE_PROCTORING_ROOM.ATTR_ID, room1.name)
.call()
.get();
assertNotNull(collection);
assertFalse(collection.isEmpty());
assertEquals(2, collection.size());
final ClientConnection connection = collection.iterator().next();
assertEquals(runningExam.id, connection.examId);
// this is because the Json model do not contian certain attributes due to performance
assertNull(connection.remoteProctoringRoomId);
// we can geht the room number by getting it directyl from the record
final ClientConnection clientConnection = this.clientConnectionDAO.byPK(connection.id).get();
assertNotNull(clientConnection.remoteProctoringRoomId);
// get and open townhall
final String townhallActive = restService
.getBuilder(IsTownhallRoomAvailable.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertEquals("true", townhallActive);
// check no Townhallroom yet
RemoteProctoringRoom townhallRoom = restService
.getBuilder(GetTownhallRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertEquals(RemoteProctoringRoom.NULL_ROOM, townhallRoom);
// open townhall room
final ProctoringRoomConnection townhallRoomConntection = restService
.getBuilder(OpenTownhallRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertNotNull(townhallRoomConntection);
// check Townhallroom is available yet
townhallRoom = restService
.getBuilder(GetTownhallRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertTrue(townhallRoom.townhallRoom);
assertEquals(townhallRoom.name, townhallRoomConntection.roomName);
// close townhall room
restService
.getBuilder(CloseProctoringRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.withQueryParam(ProctoringRoomConnection.ATTR_ROOM_NAME, townhallRoom.name)
.call()
.get();
townhallRoom = restService
.getBuilder(GetTownhallRoom.class)
.withURIVariable(API.PARAM_MODEL_ID, runningExam.getModelId())
.call()
.get();
assertEquals(RemoteProctoringRoom.NULL_ROOM, townhallRoom);
Thread.sleep(5000);
} catch (final Exception e) {
fail(e.getMessage());
}
}
@Test
@Order(29)
// *************************************
// Use Case 29: Login as admin and create some batch actions
// - Get Exam (running)
// - start some SEB clients connecting to running exam
// - Check collecting rooms created
public void testUsecase29_TestBatchAction() throws IOException, InterruptedException {
final RestServiceImpl restService = createRestServiceForUser(
"admin",
"admin",
new DoBatchAction(),
new GetBatchAction(),
new GetBatchActionPage(),
new GetExamConfigNodePage());
final ConfigurationNode config = restService
.getBuilder(GetExamConfigNodePage.class)
.call()
.getOrThrow().content
.get(0);
assertNotNull(config);
assertEquals("READY_TO_USE", config.status.toString());
// apply batch action
final Result<BatchAction> doBatchAction = restService
.getBuilder(DoBatchAction.class)
.withFormParam(Domain.BATCH_ACTION.ATTR_ACTION_TYPE, BatchActionType.EXAM_CONFIG_STATE_CHANGE.name())
.withFormParam(BATCH_ACTION.ATTR_SOURCE_IDS, config.getModelId())
.withFormParam(BatchAction.ACTION_ATTRIBUT_TARGET_STATE, ConfigurationStatus.CONSTRUCTION.name())
.call();
assertNotNull(doBatchAction);
assertFalse(doBatchAction.hasError());
final BatchAction batchAction = doBatchAction.get();
assertNotNull(batchAction);
assertNotNull(batchAction.ownerId);
assertFalse(batchAction.isFinished());
assertEquals("EXAM_CONFIG_STATE_CHANGE", batchAction.actionType.name());
Thread.sleep(1000);
final BatchAction savedBatchAction = restService
.getBuilder(GetBatchAction.class)
.withURIVariable(API.PARAM_MODEL_ID, batchAction.getModelId())
.call().get();
assertNotNull(savedBatchAction);
assertNotNull(savedBatchAction.ownerId);
assertTrue(savedBatchAction.isFinished());
assertEquals("EXAM_CONFIG_STATE_CHANGE", savedBatchAction.actionType.name());
assertNotNull(savedBatchAction.processorId);
final Page<BatchAction> page = restService
.getBuilder(GetBatchActionPage.class)
.call().get();
assertNotNull(page);
assertFalse(page.content.isEmpty());
}
@Test
@Order(30)
// *************************************
// Use Case 30: Login as admin and archive finished exam
// - Get Exam (finished), archive and check
public void testUsecase30_TestArchiveExam() throws IOException {
final RestServiceImpl restService = createRestServiceForUser(
"admin",
"admin",
new GetExamPage(),
new GetExam(),
new ArchiveExam());
final Page<Exam> finishedExams = restService
.getBuilder(GetExamPage.class)
.withQueryParam(Exam.FILTER_ATTR_STATUS, ExamStatus.FINISHED.name())
.call()
.get();
assertNotNull(finishedExams);
assertFalse(finishedExams.content.isEmpty());
final Exam exam = finishedExams.content.get(0);
assertEquals(ExamStatus.FINISHED, exam.status);
final Result<Exam> archiveCall = restService.getBuilder(ArchiveExam.class)
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call();
assertNotNull(archiveCall);
assertFalse(archiveCall.hasError());
final Exam exam2 = archiveCall.get();
assertNotNull(exam2);
assertEquals(exam.id, exam2.id);
assertEquals(ExamStatus.ARCHIVED, exam2.status);
}
@Test
@Order(31)
// *************************************
// Use Case 31: Login as admin and archive finished exam
// - Get Exam (running), archive and check not possible
public void testUsecase31_TestArchiveRunningExam_NotPossible() throws IOException {
final RestServiceImpl restService = createRestServiceForUser(
"admin",
"admin",
new GetExamPage(),
new GetExam(),
new ArchiveExam());
final Page<Exam> finishedExams = restService
.getBuilder(GetExamPage.class)
.withQueryParam(Exam.FILTER_ATTR_STATUS, ExamStatus.RUNNING.name())
.call()
.get();
assertNotNull(finishedExams);
assertFalse(finishedExams.content.isEmpty());
final Exam exam = finishedExams.content.get(0);
assertEquals(ExamStatus.RUNNING, exam.status);
final Result<Exam> archiveCall = restService.getBuilder(ArchiveExam.class)
.withURIVariable(API.PARAM_MODEL_ID, exam.getModelId())
.call();
assertNotNull(archiveCall);
assertTrue(archiveCall.hasError());
assertTrue(archiveCall.getError().getMessage().contains("Exam is in wrong status to archive"));
}
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2022 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.webservice.integration.api.admin;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.UserServiceImpl;
import ch.ethz.seb.sebserver.webservice.weblayer.api.ConfigurationAttributeController;
@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql", "classpath:data-test-additional.sql" })
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ConfigurationAttributeAPITest extends AdministrationAPIIntegrationTester {
@Autowired
private ConfigurationAttributeController configurationAttributeController;
@Autowired
private UserServiceImpl userServiceImpl;
@Mock
private HttpServletRequest mockRequest;
private final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
@Before
public void init() {
this.userServiceImpl.setAuthenticationIfAbsent(new SEBServerUser(
-1L,
new UserInfo("user1", 1L, null, "admin", null, null, null, true, null, null,
EnumSet.allOf(UserRole.class).stream().map(r -> r.name()).collect(Collectors.toSet())),
null));
Mockito.when(this.mockRequest.getQueryString()).thenReturn("");
}
@Test
@Order(1)
public void test1_GetPage() {
final Page<ConfigurationAttribute> page = this.configurationAttributeController.getPage(
1L, 0, 100, null,
new LinkedMultiValueMap<String, String>(),
this.mockRequest);
assertNotNull(page);
assertFalse(page.content.isEmpty());
assertEquals("100", String.valueOf(page.content.size()));
}
@Test
@Order(2)
public void test2_GetNames() {
Collection<EntityName> names = this.configurationAttributeController.getNames(
1L,
new LinkedMultiValueMap<String, String>(),
this.mockRequest);
assertNotNull(names);
assertFalse(names.isEmpty());
assertEquals("241", String.valueOf(names.size()));
this.params.clear();
this.params.add(ConfigurationAttribute.FILTER_ATTR_TYPE, AttributeType.CHECKBOX.name());
names = this.configurationAttributeController.getNames(
1L,
this.params,
this.mockRequest);
assertNotNull(names);
assertFalse(names.isEmpty());
assertEquals("139", String.valueOf(names.size()));
}
@Test
@Order(3)
public void test3_GetSingle() {
final ConfigurationAttribute attr = this.configurationAttributeController.getBy("1");
assertNotNull(attr);
assertEquals("hashedAdminPassword", attr.name);
}
@Test
@Order(4)
public void test4_GetList() {
List<ConfigurationAttribute> forIds = this.configurationAttributeController.getForIds("1,2");
assertNotNull(forIds);
assertEquals("2", String.valueOf(forIds.size()));
forIds = this.configurationAttributeController.getForIds(null);
assertNotNull(forIds);
assertEquals("241", String.valueOf(forIds.size()));
}
@Test
@Order(5)
public void test5_CreateAndSaveAndDelete() {
this.params.clear();
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_PARENT_ID, null);
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, "testAttribute");
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, AttributeType.CHECKBOX.name());
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_RESOURCES, "");
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_VALIDATOR, "");
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEPENDENCIES, "");
this.params.add(Domain.CONFIGURATION_ATTRIBUTE.ATTR_DEFAULT_VALUE, "true");
final ConfigurationAttribute create = this.configurationAttributeController.create(
this.params,
1L,
this.mockRequest);
assertNotNull(create);
assertNotNull(create.id);
assertEquals("testAttribute", create.name);
assertEquals("true", create.defaultValue);
final ConfigurationAttribute savePut = this.configurationAttributeController.savePut(new ConfigurationAttribute(
create.id,
null, null, null, null, null, null,
"false"));
assertNotNull(savePut);
assertNotNull(savePut.id);
assertEquals("testAttribute", savePut.name);
assertEquals("false", savePut.defaultValue);
}
@Test
@Order(6)
public void test6_NoDeletionSupport() {
try {
this.configurationAttributeController.hardDeleteAll(
Arrays.asList("1,2,3"),
false,
null,
1L);
fail("Error expected here");
} catch (final Exception e) {
assertEquals(
"No bulk action support for: BulkAction [type=HARD_DELETE, sourceType=CONFIGURATION_ATTRIBUTE, sources=[]]",
e.getMessage());
}
try {
this.configurationAttributeController.hardDelete(
"1",
false,
null);
fail("Error expected here");
} catch (final Exception e) {
assertEquals(
"No bulk action support for: BulkAction [type=HARD_DELETE, sourceType=CONFIGURATION_ATTRIBUTE, sources=[EntityName [entityType=CONFIGURATION_ATTRIBUTE, modelId=1, name=hashedAdminPassword]]]",
e.getMessage());
}
}
}

View file

@ -81,7 +81,7 @@ public class ExamJITSIProctoringServiceTest {
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn(Result.of("fbvgeghergrgrthrehreg123"));
final JitsiProctoringService examJITSIProctoringService =
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper());
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper(), null);
String accessToken = examJITSIProctoringService.createPayload(
"test-app",
@ -115,7 +115,7 @@ public class ExamJITSIProctoringServiceTest {
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn(Result.of("fbvgeghergrgrthrehreg123"));
final JitsiProctoringService examJITSIProctoringService =
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper());
new JitsiProctoringService(null, null, cryptorMock, null, new JSONMapper(), null);
final ProctoringRoomConnection data = examJITSIProctoringService.createProctoringConnection(
"connectionToken",
"https://seb-jitsi.example.ch",
@ -160,7 +160,7 @@ public class ExamJITSIProctoringServiceTest {
examSessionService,
cryptor,
clientHttpRequestFactoryService,
jsonMapper);
jsonMapper, null);
}
}

View file

@ -556,7 +556,6 @@ CREATE TABLE IF NOT EXISTS `seb_client_configuration` (
-- -----------------------------------------------------
-- Table `webservice_server_info`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `webservice_server_info` ;
CREATE TABLE IF NOT EXISTS `webservice_server_info` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,