integration tests for GUI and code cleanup

This commit is contained in:
anhefti 2019-02-27 15:50:15 +01:00
parent 1e7b6f807f
commit 360f6d6755
15 changed files with 369 additions and 67 deletions

View file

@ -30,7 +30,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
import ch.ethz.seb.sebserver.gui.widget.ImageUpload;
import ch.ethz.seb.sebserver.gui.widget.MultiSelection;
@ -47,17 +46,9 @@ public final class Form implements FormBinding {
private final Map<String, List<Form>> subLists = new LinkedHashMap<>();
private final Map<String, Set<String>> groups = new LinkedHashMap<>();
private final EntityKey entityKey;
Form(final JSONMapper jsonMapper, final EntityKey entityKey) {
Form(final JSONMapper jsonMapper) {
this.jsonMapper = jsonMapper;
this.objectRoot = this.jsonMapper.createObjectNode();
this.entityKey = entityKey;
}
@Override
public EntityKey entityKey() {
return this.entityKey;
}
@Override

View file

@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
@ -50,7 +49,6 @@ public class FormBuilder {
private boolean emptyCellSeparation = true;
FormBuilder(
final EntityKey entityKey,
final JSONMapper jsonMapper,
final WidgetFactory widgetFactory,
final PolyglotPageService polyglotPageService,
@ -60,7 +58,7 @@ public class FormBuilder {
this.widgetFactory = widgetFactory;
this.polyglotPageService = polyglotPageService;
this.pageContext = pageContext;
this.form = new Form(jsonMapper, entityKey);
this.form = new Form(jsonMapper);
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
final GridLayout layout = new GridLayout(rows, true);

View file

@ -97,7 +97,7 @@ public class FormHandle<T extends Entity> {
fieldAccessor.setError(this.i18nSupport.getText(new LocTextKey(
FIELD_VALIDATION_LOCTEXT_PREFIX + valError.errorType,
(Object[]) valError.attributes)));
(Object[]) valError.getAttributes())));
}
public FormHandle<T> process(final Consumer<Form> consumer) {

View file

@ -12,7 +12,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
@ -42,21 +41,6 @@ public class PageFormService {
final int rows) {
return new FormBuilder(
pageContext.getEntityKey(),
this.jsonMapper,
this.widgetFactory,
this.polyglotPageService,
pageContext,
rows);
}
public FormBuilder getBuilder(
final EntityKey entityKey,
final PageContext pageContext,
final int rows) {
return new FormBuilder(
entityKey,
this.jsonMapper,
this.widgetFactory,
this.polyglotPageService,

View file

@ -8,7 +8,10 @@
package ch.ethz.seb.sebserver.gui.service.page;
import java.util.Collection;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.util.Utils;
public class FieldValidationError {
@ -16,7 +19,7 @@ public class FieldValidationError {
public final String domainName;
public final String fieldName;
public final String errorType;
public final String[] attributes;
public final Collection<String> attributes;
public FieldValidationError(final APIMessage apiMessage) {
this(
@ -29,11 +32,19 @@ public class FieldValidationError {
final String[] attributes) {
this.messageCode = messageCode;
this.attributes = attributes;
this.attributes = Utils.immutableCollectionOf(attributes);
this.domainName = (attributes != null && attributes.length > 0) ? attributes[0] : null;
this.fieldName = (attributes != null && attributes.length > 1) ? attributes[1] : null;
this.errorType = (attributes != null && attributes.length > 2) ? attributes[2] : null;
}
public String[] getAttributes() {
if (this.attributes == null) {
return new String[0];
}
return this.attributes.toArray(new String[this.attributes.size()]);
}
}

View file

@ -8,12 +8,8 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
public interface FormBinding {
EntityKey entityKey();
String getFormAsJson();
String getFormUrlEncoded();

View file

@ -28,11 +28,9 @@ import org.springframework.web.client.RestClientResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
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.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder;
@ -72,7 +70,7 @@ public abstract class RestCall<T> {
log.debug("Call webservice API on {} for {}", this.path, builder);
try {
final ResponseEntity<String> responseEntity = RestCall.this.restService
final ResponseEntity<String> responseEntity = this.restService
.getWebserviceAPIRestTemplate()
.exchange(
builder.buildURI(),
@ -211,10 +209,8 @@ public abstract class RestCall<T> {
}
public RestCallBuilder withFormBinding(final FormBinding formBinding) {
final EntityKey entityKey = formBinding.entityKey();
if (entityKey != null) {
return withURIVariable(API.PARAM_MODEL_ID, formBinding.entityKey().modelId)
.withBody(formBinding.getFormAsJson());
if (RestCall.this.httpMethod == HttpMethod.PUT) {
return withBody(formBinding.getFormAsJson());
} else {
this.body = formBinding.getFormUrlEncoded();
return this;

View file

@ -9,13 +9,9 @@
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@ -23,8 +19,6 @@ import org.springframework.web.util.UriComponentsBuilder;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
@ -33,8 +27,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURISer
@GuiProfile
public class RestService {
private static final Logger log = LoggerFactory.getLogger(RestService.class);
private final AuthorizationContextHolder authorizationContextHolder;
private final WebserviceURIService webserviceURIBuilderSupplier;
private final Map<String, RestCall<?>> calls;
@ -80,19 +72,4 @@ public class RestService {
return restCall.newBuilder();
}
public final List<Tuple<String>> getInstitutionSelection() {
try {
return getBuilder(GetInstitutionNames.class)
.call()
.map(list -> list
.stream()
.map(entityName -> new Tuple<>(entityName.modelId, entityName.name))
.collect(Collectors.toList()))
.getOrThrow();
} catch (final Exception e) {
log.error("Failed to get selection resource for Institution selection", e);
return Collections.emptyList();
}
}
}

View file

@ -98,6 +98,7 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
this.guiClientSecret,
this.webserviceURIService,
this.clientHttpRequestFactory);
session.setAttribute(CONTEXT_HOLDER_ATTRIBUTE, context);
}

View file

@ -8,6 +8,9 @@
package ch.ethz.seb.sebserver.gbl.model.institution;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.junit.Test;
@ -21,10 +24,13 @@ public class InstitutionTest {
@Test
public void test() throws JsonParseException, JsonMappingException, IOException {
final String testJson = "{\"id\":\"1\",\"name\":\"ETH Zürichrgerg\",\"urlSuffix\":\"\"}";
final String testJson = "{\"id\":\"1\",\"name\":\"ETH Zürich\",\"urlSuffix\":\"\"}";
final JSONMapper mapper = new JSONMapper();
final Institution inst = mapper.readValue(testJson, Institution.class);
assertTrue(inst.id != null);
assertTrue(inst.id.longValue() == 1);
assertEquals("ETH Zürich", inst.name);
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.gui.form;
import org.junit.Test;
public class FormBuilderTest {
@Test
public void testFormBuilder() {
// final PolyglotPageService polyglotPageService = Mockito.mock(PolyglotPageService.class);
// final ServerPushService serverPushService = Mockito.mock(ServerPushService.class);
// final WidgetFactory WidgetFactory = new WidgetFactory(polyglotPageService, serverPushService);
//
// final PageFormService pageFormService = new PageFormService(
// new JSONMapper(),
// WidgetFactory,
// polyglotPageService);
//
// final PageContext formContext = Mockito.mock(PageContext.class);
// final SaveInstitution rest = Mockito.mock(SaveInstitution.class);
//
// final Composite content = Mockito.mock(Composite.class);
//
// final FormHandle<Institution> formHandle = pageFormService.getBuilder(
// formContext.copyOf(content), 4)
// .readonly(formContext.isReadonly())
// .putStaticValue(Domain.INSTITUTION.ATTR_ID, "1")
// .addField(FormBuilder.text(
// Domain.INSTITUTION.ATTR_NAME,
// "sebserver.institution.form.name",
// "Test Institution"))
// .addField(FormBuilder.text(
// Domain.INSTITUTION.ATTR_URL_SUFFIX,
// "sebserver.institution.form.urlSuffix",
// "inst"))
// .addField(FormBuilder.imageUpload(
// Domain.INSTITUTION.ATTR_LOGO_IMAGE,
// "sebserver.institution.form.logoImage",
// ""))
// .buildFor(rest);
//
// assertNotNull(formHandle);
}
}

View file

@ -0,0 +1,68 @@
/*
* 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.gui.integration;
import static org.junit.Assert.*;
import org.junit.Test;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.OAuth2AuthorizationContextHolder;
public class CurrentUserTest extends GuiIntegrationTest {
@Test
public void testCurrentUserLoginAndGet() {
final OAuth2AuthorizationContextHolder authorizationContextHolder = getAuthorizationContextHolder();
final CurrentUser currentUser = new CurrentUser(authorizationContextHolder);
// no user is logged in for now
assertNull(currentUser.get());
// login as SEB Administrator
authorizationContextHolder.getAuthorizationContext().login("admin", "admin");
final UserInfo userInfo = currentUser.getOrHandleError(error -> {
fail("expecting no error here");
return null;
});
assertNotNull(userInfo);
assertEquals("user1", userInfo.uuid);
}
@Test
public void testCurrentUserPrivileges() {
final OAuth2AuthorizationContextHolder authorizationContextHolder = getAuthorizationContextHolder();
final CurrentUser currentUser = new CurrentUser(authorizationContextHolder);
// login as SEB Administrator
authorizationContextHolder.getAuthorizationContext().login("admin", "admin");
assertTrue(currentUser.hasBasePrivilege(PrivilegeType.READ_ONLY, EntityType.INSTITUTION));
assertTrue(currentUser.hasPrivilege(PrivilegeType.WRITE, currentUser.get()));
assertTrue(currentUser.hasBasePrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION));
assertTrue(currentUser.hasInstitutionalPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION));
}
@Test
public void testCurrentUserLogin() {
final OAuth2AuthorizationContextHolder authorizationContextHolder = login("admin", "admin");
final CurrentUser currentUser = new CurrentUser(authorizationContextHolder);
final UserInfo userInfo = currentUser.getOrHandleError(error -> {
fail("expecting no error here");
return null;
});
assertNotNull(userInfo);
assertEquals("user1", userInfo.uuid);
}
}

View file

@ -0,0 +1,121 @@
/*
* 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.gui.integration;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.HttpURLConnection;
import javax.servlet.http.HttpSession;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import ch.ethz.seb.sebserver.SEBServer;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.OAuth2AuthorizationContextHolder;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = SEBServer.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("test")
@AutoConfigureMockMvc
public abstract class GuiIntegrationTest {
@Value("${sebserver.webservice.api.admin.clientId}")
protected String clientId;
@Value("${sebserver.webservice.api.admin.clientSecret}")
protected String clientSecret;
@Value("${sebserver.webservice.api.admin.endpoint}")
protected String endpoint;
@Autowired
protected WebApplicationContext wac;
@Autowired
protected JSONMapper jsonMapper;
@Autowired
protected FilterChainProxy springSecurityFilterChain;
protected MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.addFilter(this.springSecurityFilterChain).build();
}
protected OAuth2AuthorizationContextHolder getAuthorizationContextHolder() {
final HttpSession sessionMock = Mockito.mock(HttpSession.class);
final WebserviceURIService webserviceURIService = new WebserviceURIService(
"http", "localhost", "8080", this.endpoint);
return new OAuth2AuthorizationContextHolder(
this.clientId,
this.clientSecret,
webserviceURIService,
new SimpleClientHttpRequestFactory() {
@Override
protected void prepareConnection(
final HttpURLConnection connection,
final String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
connection.setInstanceFollowRedirects(false);
}
}) {
private SEBServerAuthorizationContext authContext = null;
@Override
public SEBServerAuthorizationContext getAuthorizationContext() {
if (this.authContext == null) {
this.authContext = super.getAuthorizationContext(sessionMock);
}
return this.authContext;
}
};
}
protected SEBServerAuthorizationContext getAuthorizationContext() {
final SEBServerAuthorizationContext authorizationContext =
getAuthorizationContextHolder().getAuthorizationContext();
assertNotNull(authorizationContext);
return authorizationContext;
}
protected OAuth2AuthorizationContextHolder login(final String name, final String pwd) {
final OAuth2AuthorizationContextHolder authorizationContextHolder = getAuthorizationContextHolder();
final SEBServerAuthorizationContext authorizationContext = authorizationContextHolder.getAuthorizationContext();
if (authorizationContext.isLoggedIn()) {
throw new IllegalStateException("another user is already logged in");
}
authorizationContext.login(name, pwd);
return authorizationContextHolder;
}
}

View file

@ -0,0 +1,63 @@
/*
* 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.gui.integration;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.OAuth2AuthorizationContextHolder;
public class RestServiceTest extends GuiIntegrationTest {
@Test
public void testRestServiceInit() {
final OAuth2AuthorizationContextHolder authorizationContextHolder = login("admin", "admin");
final Collection<RestCall<?>> calls = new ArrayList<>();
calls.add(new RestServiceTest.GetInstitution());
final RestService restService = new RestService(authorizationContextHolder, new JSONMapper(), calls);
final Result<Institution> call = restService.getBuilder(RestServiceTest.GetInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, "2")
.call();
assertNotNull(call);
assertFalse(call.hasError());
final Institution institution = call.get();
assertEquals("Institution2", institution.name);
}
public static class GetInstitution extends RestCall<Institution> {
public GetInstitution() {
super(
new TypeReference<Institution>() {
},
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.INSTITUTION_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}
}

View file

@ -0,0 +1,37 @@
/*
* 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.gui.integration;
import static org.junit.Assert.*;
import org.junit.Test;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.SEBServerAuthorizationContext;
public class SEBServerAuthorizationContextTest extends GuiIntegrationTest {
@Test
public void testLoginLogoutAsSEBAdmin() {
final SEBServerAuthorizationContext authorizationContext = getAuthorizationContext();
assertTrue(authorizationContext.login("admin", "admin"));
assertTrue(authorizationContext.isLoggedIn());
final Result<UserInfo> loggedInUser = authorizationContext.getLoggedInUser();
assertFalse(loggedInUser.hasError());
final UserInfo userInfo = loggedInUser.get();
assertEquals("user1", userInfo.uuid);
assertTrue(authorizationContext.logout());
assertFalse(authorizationContext.isLoggedIn());
}
}