From 44dbe1e714a1825ab9639d8002e8488eba8fb6a0 Mon Sep 17 00:00:00 2001 From: anhefti Date: Sun, 3 Feb 2019 14:41:48 +0100 Subject: [PATCH] more tests and fixes --- pom.xml | 8 +- .../gbl/model/institution/Institution.java | 4 +- .../gbl/model/institution/LmsSetup.java | 5 +- .../sebserver/gbl/model/user/UserInfo.java | 2 + .../seb/sebserver/gbl/model/user/UserMod.java | 10 +- .../InternalEncryptionService.java | 12 +- .../dao/impl/LmsSetupDAOImpl.java | 29 +-- .../gbl/model/institution/LmsSetupTest.java | 32 +++ .../api/admin/LmsSetupAPITest.java | 199 ++++++++++++++++++ .../resources/application-test.properties | 2 +- 10 files changed, 256 insertions(+), 47 deletions(-) create mode 100644 src/test/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTest.java create mode 100644 src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/LmsSetupAPITest.java diff --git a/pom.xml b/pom.xml index 557e373d..c7d905e6 100644 --- a/pom.xml +++ b/pom.xml @@ -152,10 +152,10 @@ ch/ethz/seb/sebserver/* - - ch/ethz/seb/sebserver/webservice/datalayer/batis/mapper/* - ch/ethz/seb/sebserver/webservice/datalayer/batis/model/* - + + + + diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java index 157330f5..36133067 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/Institution.java @@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gbl.model.institution; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; @@ -26,7 +27,7 @@ public final class Institution implements GrantEntity, Activatable { public final Long id; @JsonProperty(INSTITUTION.ATTR_NAME) - @NotNull + @NotNull(message = "institution:name:notNull") @Size(min = 3, max = 255, message = "institution:name:size:{min}:{max}:${validatedValue}") public final String name; @@ -40,6 +41,7 @@ public final class Institution implements GrantEntity, Activatable { @JsonProperty(INSTITUTION.ATTR_ACTIVE) public final Boolean active; + @JsonCreator public Institution( @JsonProperty(Domain.ATTR_ID) final Long id, @JsonProperty(INSTITUTION.ATTR_NAME) final String name, diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java index 3abd14d3..01efa743 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetup.java @@ -42,12 +42,12 @@ public final class LmsSetup implements GrantEntity, Activatable { public final Long institutionId; @JsonProperty(LMS_SETUP.ATTR_NAME) - @NotNull + @NotNull(message = "lmsSetup:name:notNull") @Size(min = 3, max = 255, message = "lmsSetup:name:size:{min}:{max}:${validatedValue}") public final String name; @JsonProperty(LMS_SETUP.ATTR_LMS_TYPE) - @NotNull + @NotNull(message = "lmsSetup:lmsType:notNull") public final LmsType lmsType; @JsonProperty(LMS_SETUP.ATTR_LMS_CLIENTNAME) @@ -59,7 +59,6 @@ public final class LmsSetup implements GrantEntity, Activatable { public final String lmsAuthSecret; @JsonProperty(LMS_SETUP.ATTR_LMS_URL) - @NotNull public final String lmsApiUrl; @JsonProperty(LMS_SETUP.ATTR_LMS_REST_API_TOKEN) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java index 7573a84f..b6a83c1a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserInfo.java @@ -16,6 +16,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.joda.time.DateTimeZone; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import ch.ethz.seb.sebserver.gbl.model.Activatable; @@ -76,6 +77,7 @@ public final class UserInfo implements GrantEntity, Activatable, Serializable { public final Set roles; @JsonCreator + @JsonIgnoreProperties(ignoreUnknown = true) public UserInfo( @JsonProperty(USER.ATTR_UUID) final String uuid, @JsonProperty(USER.ATTR_INSTITUTION_ID) final Long institutionId, diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java index 1bcaae3e..16128e59 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserMod.java @@ -22,9 +22,9 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.Domain.USER; import ch.ethz.seb.sebserver.gbl.model.Domain.USER_ROLE; -import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.model.EntityType; import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.GrantEntity; @@ -41,13 +41,13 @@ public final class UserMod implements GrantEntity { public final Long institutionId; /** Full name of the user */ - @NotNull + @NotNull(message = "user:name:notNull") @Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}") @JsonProperty(USER.ATTR_NAME) public final String name; /** The internal user name */ - @NotNull + @NotNull(message = "user:username:notNull") @Size(min = 3, max = 255, message = "user:username:size:{min}:{max}:${validatedValue}") @JsonProperty(USER.ATTR_USERNAME) public final String username; @@ -58,12 +58,12 @@ public final class UserMod implements GrantEntity { public final String email; /** The users locale */ - @NotNull + @NotNull(message = "user:locale:notNull") @JsonProperty(USER.ATTR_LOCALE) public final Locale locale; /** The users time zone */ - @NotNull + @NotNull(message = "user:timeZone:notNull") @JsonProperty(USER.ATTR_TIMEZONE) public final DateTimeZone timeZone; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/InternalEncryptionService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/InternalEncryptionService.java index a23396db..26bc9744 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/InternalEncryptionService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/InternalEncryptionService.java @@ -39,7 +39,7 @@ public class InternalEncryptionService { NO_SALT).encrypt(text); } catch (final Exception e) { log.error("Failed to encrypt text: ", e); - return null; + return text; } } @@ -50,7 +50,7 @@ public class InternalEncryptionService { NO_SALT).decrypt(text); } catch (final Exception e) { log.error("Failed to decrypt text: ", e); - return null; + return text; } } @@ -61,7 +61,7 @@ public class InternalEncryptionService { salt).encrypt(text); } catch (final Exception e) { log.error("Failed to encrypt text: ", e); - return null; + return text; } } @@ -72,7 +72,7 @@ public class InternalEncryptionService { salt).decrypt(text); } catch (final Exception e) { log.error("Failed to decrypt text: ", e); - return null; + return text; } } @@ -81,7 +81,7 @@ public class InternalEncryptionService { return Encryptors.text(secret, salt).encrypt(text); } catch (final Exception e) { log.error("Failed to encrypt text: ", e); - return null; + return text; } } @@ -90,7 +90,7 @@ public class InternalEncryptionService { return Encryptors.text(secret, salt).decrypt(text); } catch (final Exception e) { log.error("Failed to decrypt text: ", e); - return null; + return text; } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java index 187e4df7..cc3de0f4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/LmsSetupDAOImpl.java @@ -286,37 +286,12 @@ public class LmsSetupDAOImpl implements LmsSetupDAO { record.getName(), LmsType.valueOf(record.getLmsType()), record.getLmsClientname(), - record.getLmsClientsecret(), + null, record.getLmsUrl(), record.getLmsRestApiToken(), record.getSebClientname(), - record.getSebClientsecret(), + null, BooleanUtils.toBooleanObject(record.getActive()))); } -// private LmsSetup handlePasswortReset(LmsSetup lmsSetup) { -// String lmsPWDEncrypted = null; -// String sebPWDEncrypted = null; -// if (StringUtils.isNotBlank(lmsSetup.lmsAuthName) && StringUtils.isNotBlank(lmsSetup.lmsAuthSecret)) { -// -// } -// -// if (StringUtils.isNotBlank(lmsSetup.sebAuthName) && StringUtils.isNotBlank(lmsSetup.sebAuthSecret)) { -// -// } -// -// return new LmsSetup( -// lmsSetup.id, -// lmsSetup.institutionId, -// lmsSetup.name, -// lmsSetup.lmsType, -// lmsSetup.lmsAuthName, -// lmsPWDEncrypted, -// lmsSetup.lmsApiUrl, -// lmsSetup.lmsRestApiToken, -// lmsSetup.sebAuthName, -// sebPWDEncrypted, -// lmsSetup.active); -// } - } diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTest.java new file mode 100644 index 00000000..8c8e434c --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/model/institution/LmsSetupTest.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 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.gbl.model.institution; + +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; + +import org.junit.Test; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class LmsSetupTest { + + @Test + public void testDeserialization() throws JsonParseException, JsonMappingException, IOException { + final String jsonString = + "{\"id\":1,\"institutionId\":1,\"name\":\"new LmsSetup 1\",\"lmsType\":\"MOCKUP\",\"lmsClientname\":\"lms1Name\",\"lmsClientsecret\":\"lms1Secret\",\"lmsUrl\":\"https://www.lms1.com\",\"lmsRestApiToken\":null,\"sebClientname\":\"seb1Name\",\"sebClientsecret\":\"seb1Secret\",\"active\":false}"; + + final LmsSetup lmsSetup = new ObjectMapper().readValue(jsonString, LmsSetup.class); + assertNotNull(lmsSetup); + } + +} diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/LmsSetupAPITest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/LmsSetupAPITest.java new file mode 100644 index 00000000..3a1c3291 --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/integration/api/admin/LmsSetupAPITest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2019 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.Assert.*; + +import java.util.List; + +import org.junit.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.jdbc.Sql; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.APIMessage; +import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; +import ch.ethz.seb.sebserver.gbl.model.Domain; +import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup; +import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType; + +@Sql(scripts = { "classpath:schema-test.sql", "classpath:data-test.sql" }) +public class LmsSetupAPITest extends AdministrationAPIIntegrationTester { + + @Test + public void testCreateModifyActivateDelete() throws Exception { + // Institutional admin 1 create a LMSSetup + + // create new institution with seb-admin + LmsSetup lmsSetup = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) + .withMethod(HttpMethod.POST) + .withAttribute("name", "new LmsSetup 1") + .withAttribute(Domain.LMS_SETUP.ATTR_LMS_TYPE, LmsType.MOCKUP.name()) + .withAttribute("active", "false") + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(lmsSetup); + assertNotNull(lmsSetup.id); + assertTrue(lmsSetup.institutionId.longValue() == 1); + assertEquals("new LmsSetup 1", lmsSetup.name); + assertTrue(LmsType.MOCKUP == lmsSetup.lmsType); + assertFalse(lmsSetup.active); + + // set lms server and credentials + final LmsSetup modified = new LmsSetup( + lmsSetup.id, + lmsSetup.institutionId, + lmsSetup.name, + lmsSetup.lmsType, + "lms1Name", + "lms1Secret", + "https://www.lms1.com", + null, + "seb1Name", + "seb1Secret", + null); + + lmsSetup = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP + "/" + lmsSetup.id) + .withMethod(HttpMethod.PUT) + .withBodyJson(modified) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(lmsSetup); + assertNotNull(lmsSetup.id); + assertTrue(lmsSetup.institutionId.longValue() == 1); + assertEquals("new LmsSetup 1", lmsSetup.name); + assertTrue(LmsType.MOCKUP == lmsSetup.lmsType); + assertEquals("lms1Name", lmsSetup.lmsAuthName); + assertEquals("seb1Name", lmsSetup.sebAuthName); + // secrets, once set are not exposed + assertEquals(null, lmsSetup.lmsAuthSecret); + assertEquals(null, lmsSetup.sebAuthSecret); + assertFalse(lmsSetup.active); + + // activate + EntityProcessingReport report = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) + .withPath("/").withPath(String.valueOf(lmsSetup.id)).withPath("/active") + .withMethod(HttpMethod.POST) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(report); + assertNotNull(report.source); + assertTrue(report.source.size() == 1); + assertEquals(String.valueOf(lmsSetup.id), report.source.iterator().next().modelId); + assertEquals("[]", report.dependencies.toString()); + assertEquals("[]", report.errors.toString()); + + // get + lmsSetup = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP).withPath("/") + .withPath(String.valueOf(lmsSetup.id)) + .withMethod(HttpMethod.GET) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(lmsSetup); + assertTrue(lmsSetup.active); + + // deactivate + report = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) + .withPath("/").withPath(String.valueOf(lmsSetup.id)).withPath("/inactive") + .withMethod(HttpMethod.POST) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(report); + assertNotNull(report.source); + assertTrue(report.source.size() == 1); + assertEquals(String.valueOf(lmsSetup.id), report.source.iterator().next().modelId); + assertEquals("[]", report.dependencies.toString()); + assertEquals("[]", report.errors.toString()); + + lmsSetup = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP).withPath("/") + .withPath(String.valueOf(lmsSetup.id)) + .withMethod(HttpMethod.GET) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(lmsSetup); + assertFalse(lmsSetup.active); + + // delete + report = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) + .withPath("/").withPath(String.valueOf(lmsSetup.id)) + .withMethod(HttpMethod.DELETE) + .withExpectedStatus(HttpStatus.OK) + .getAsObject(new TypeReference() { + }); + + assertNotNull(report); + assertNotNull(report.source); + assertTrue(report.source.size() == 1); + assertEquals(String.valueOf(lmsSetup.id), report.source.iterator().next().modelId); + assertEquals("[]", report.dependencies.toString()); + assertEquals("[]", report.errors.toString()); + + // get + final List error = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP).withPath("/") + .withPath(String.valueOf(lmsSetup.id)) + .withMethod(HttpMethod.GET) + .withExpectedStatus(HttpStatus.NOT_FOUND) + .getAsObject(new TypeReference>() { + }); + + assertNotNull(error); + assertTrue(error.size() > 0); + assertEquals("Resource LMS_SETUP with ID: 1 not found", error.get(0).details); + } + + @Test + public void testValidationOnCreate() throws Exception { + // create new institution with seb-admin + final List errors = new RestAPITestHelper() + .withAccessToken(getAdminInstitution1Access()) + .withPath(SEBServerRestEndpoints.ENDPOINT_LMS_SETUP) + .withMethod(HttpMethod.POST) + .withAttribute("name", "new LmsSetup 1") + .withAttribute("active", "false") + .getAsObject(new TypeReference>() { + }); + + assertNotNull(errors); + assertTrue(errors.size() == 1); + assertEquals("Field validation error", errors.get(0).systemMessage); + assertEquals("[lmsSetup, lmsType, notNull]", String.valueOf(errors.get(0).attributes)); + } + +} diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties index cc85e990..7ff71ccf 100644 --- a/src/test/resources/application-test.properties +++ b/src/test/resources/application-test.properties @@ -16,5 +16,5 @@ sebserver.webservice.api.admin.refreshTokenValiditySeconds=-1 sebserver.webservice.api.exam.endpoint=/exam-api sebserver.webservice.api.exam.accessTokenValiditySeconds=1800 sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1 - +sebserver.webservice.internalSecret=TO_SET sebserver.webservice.api.redirect.unauthorized=none