From ea29c374c25494f7e9c5ddc27b14127057982fac Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 11 Dec 2020 15:12:24 +0300 Subject: [PATCH 01/32] refactor: extract common config functionality and introduce add config part of #9417 --- .../function/DeploymentConfiguration.java | 39 ++++++++----------- .../PropertyDeploymentConfiguration.java | 10 +++-- .../startup/AbstractConfigurationFactory.java | 12 +----- 3 files changed, 24 insertions(+), 37 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java index 3f69e2b6ce9..22aacf3efdc 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java @@ -166,26 +166,6 @@ public interface DeploymentConfiguration T getApplicationOrSystemProperty(String propertyName, T defaultValue, Function converter); - /** - * A shorthand of - * {@link DeploymentConfiguration#getApplicationOrSystemProperty(String, Object, Function)} - * for {@link String} type. - * - * @param propertyName - * The simple of the property, in some contexts, lookup might be - * performed using variations of the provided name. - * @param defaultValue - * the default value that should be used if no value has been - * defined - * @return the property value, or the passed default value if no property - * value is found - */ - @Override - default String getStringProperty(String propertyName, String defaultValue) { - return getApplicationOrSystemProperty(propertyName, defaultValue, - Function.identity()); - } - /** * A shorthand of * {@link DeploymentConfiguration#getApplicationOrSystemProperty(String, Object, Function)} @@ -297,9 +277,22 @@ default List getPolyfills() { } /** - * Get if the dev server should be reused on each reload. True by default, - * set it to false in tests so as dev server is not kept as a daemon after - * the test. + * <<<<<<< Upstream, based on master ======= Get if the dev server should be + * enabled. True by default + * + * @return true if dev server should be used + */ + @Override + default boolean enableDevServer() { + return getBooleanProperty( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, true); + } + + /** + * >>>>>>> 01eb234 refactor: extract common config functionality and + * introduce add config Get if the dev server should be reused on each + * reload. True by default, set it to false in tests so as dev server is not + * kept as a daemon after the test. * * @return true if dev server should be reused */ diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index e2d95978044..6281cf30136 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -22,6 +22,7 @@ import java.util.Properties; import com.vaadin.flow.function.DeploymentConfiguration; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.shared.communication.PushMode; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS; @@ -47,7 +48,9 @@ public class PropertyDeploymentConfiguration /** * Create a new property deployment configuration instance. - * + * + * @param parentConfig + * a parent application configuration * @param systemPropertyBaseClass * the class that should be used as a basis when reading system * properties @@ -55,8 +58,9 @@ public class PropertyDeploymentConfiguration * the init parameters that should make up the foundation for * this configuration */ - public PropertyDeploymentConfiguration(Class systemPropertyBaseClass, - Properties initParameters) { + public PropertyDeploymentConfiguration( + ApplicationConfiguration parentConfig, + Class systemPropertyBaseClass, Properties initParameters) { super(filterStringProperties(initParameters)); initialParameters = initParameters; this.systemPropertyBaseClass = systemPropertyBaseClass; diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java index 91c01ca7c41..1519f82c6da 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -62,7 +62,7 @@ public class AbstractConfigurationFactory implements Serializable { * the token file data * @return the config parameters */ - public Map getConfigParametersUsingTokenData( + protected Map getConfigParametersUsingTokenData( JsonObject buildInfo) { Map params = new HashMap<>(); if (buildInfo.hasKey(SERVLET_PARAMETER_PRODUCTION_MODE)) { @@ -151,16 +151,6 @@ public Map getConfigParametersUsingTokenData( return params; } - /** - * Sets to the dev mode properties to the configuration parameters. - * - * @see #getConfigParametersUsingTokenData(JsonObject) - * - * @param params - * the configuration parameters to set dev mode properties to - * @param buildInfo - * the token file data - */ protected void setDevModePropertiesUsingTokenData( Map params, JsonObject buildInfo) { // read dev mode properties from the token and set init parameter only From 9c4187386d31b93898460ad95c5fda4b6c0c87fb Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 11 Dec 2020 15:13:14 +0300 Subject: [PATCH 02/32] refactor: use application level configuration instead of deployment conf --- .../DefaultDeploymentConfiguration.java | 23 ++- .../DeploymentConfigurationFactory.java | 193 ++---------------- .../vaadin/flow/server/DevModeHandler.java | 5 +- .../server/startup/DevModeInitializer.java | 58 ++---- .../flow/server/startup/ServletDeployer.java | 15 +- .../startup/VaadinAppShellInitializer.java | 23 +-- 6 files changed, 71 insertions(+), 246 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java index e0227c0a10b..a94ab8229ed 100755 --- a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import com.vaadin.flow.function.DeploymentConfiguration; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.shared.communication.PushMode; import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_FRONTEND_DIR; @@ -56,7 +57,8 @@ public class DefaultDeploymentConfiguration + "Client-side views written in TypeScript are not supported. Vaadin 15+ enables client-side and server-side views.\n" + "See https://vaadin.com/docs/v15/flow/typescript/starting-the-app.html for more information."; - // not a warning anymore, but keeping variable name to avoid breaking anything + // not a warning anymore, but keeping variable name to avoid breaking + // anything public static final String WARNING_V15_BOOTSTRAP = "Using Vaadin 15+ bootstrap mode.%n %s%n %s"; private static final String DEPLOYMENT_WARNINGS = "Following issues were discovered with deployment configuration:"; @@ -128,8 +130,8 @@ public class DefaultDeploymentConfiguration * the init parameters that should make up the foundation for * this configuration */ - public DefaultDeploymentConfiguration(Class systemPropertyBaseClass, - Properties initParameters) { + public DefaultDeploymentConfiguration(ApplicationConfiguration parentConfig, + Class systemPropertyBaseClass, Properties initParameters) { super(systemPropertyBaseClass, initParameters); boolean log = logging.getAndSet(false); @@ -362,7 +364,8 @@ private String getIndexHTMLMessage(String frontendDir) { */ private void checkRequestTiming() { requestTiming = getBooleanProperty( - InitParameters.SERVLET_PARAMETER_REQUEST_TIMING, !productionMode); + InitParameters.SERVLET_PARAMETER_REQUEST_TIMING, + !productionMode); } /** @@ -370,7 +373,8 @@ private void checkRequestTiming() { */ private void checkXsrfProtection(boolean loggWarning) { xsrfProtectionEnabled = !getBooleanProperty( - InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, false); + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + false); if (!xsrfProtectionEnabled && loggWarning) { warnings.add(WARNING_XSRF_PROTECTION_DISABLED); } @@ -422,9 +426,9 @@ private void checkCloseIdleSessions() { private void checkPushMode() { try { pushMode = getApplicationOrSystemProperty( - InitParameters.SERVLET_PARAMETER_PUSH_MODE, PushMode.DISABLED, - stringMode -> Enum.valueOf(PushMode.class, - stringMode.toUpperCase())); + InitParameters.SERVLET_PARAMETER_PUSH_MODE, + PushMode.DISABLED, stringMode -> Enum + .valueOf(PushMode.class, stringMode.toUpperCase())); } catch (IllegalArgumentException e) { warnings.add(WARNING_PUSH_MODE_NOT_RECOGNIZED); pushMode = PushMode.DISABLED; @@ -432,7 +436,8 @@ private void checkPushMode() { } private void checkPushURL() { - pushURL = getStringProperty(InitParameters.SERVLET_PARAMETER_PUSH_URL, ""); + pushURL = getStringProperty(InitParameters.SERVLET_PARAMETER_PUSH_URL, + ""); } private void checkSyncIdCheck() { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index 57f9beff739..c44355e6e89 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -22,12 +22,9 @@ import java.io.UncheckedIOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Enumeration; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Properties; @@ -36,21 +33,17 @@ import org.slf4j.LoggerFactory; import com.vaadin.flow.component.UI; -import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.di.ResourceProvider; import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.internal.AnnotationReader; import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; import com.vaadin.flow.server.startup.AbstractConfigurationFactory; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; -import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_TOKEN_FILE; -import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; /** * Creates {@link DeploymentConfiguration} filled with all parameters specified @@ -58,7 +51,8 @@ * * @since 1.2 */ -public final class DeploymentConfigurationFactory implements Serializable { +public class DeploymentConfigurationFactory extends AbstractConfigurationFactory + implements Serializable { public static final Object FALLBACK_CHUNK = new Serializable() { }; @@ -67,14 +61,9 @@ public final class DeploymentConfigurationFactory implements Serializable { + "the project/working directory. Ensure 'webpack.config.js' is present or trigger creation of " + "'flow-build-info.json' via running 'prepare-frontend' Maven goal."; - public static final String DEV_FOLDER_MISSING_MESSAGE = "Running project in development mode with no access to folder '%s'.%n" - + "Build project in production mode instead, see https://vaadin.com/docs/v15/flow/production/tutorial-production-mode-basic.html"; private static final Logger logger = LoggerFactory .getLogger(DeploymentConfigurationFactory.class); - private DeploymentConfigurationFactory() { - } - /** * Creates a {@link DeploymentConfiguration} instance that is filled with * all parameters, specified for the current app. @@ -87,10 +76,12 @@ private DeploymentConfigurationFactory() { * @throws VaadinConfigurationException * thrown if property construction fails */ - public static DeploymentConfiguration createDeploymentConfiguration( + public DeploymentConfiguration createDeploymentConfiguration( Class systemPropertyBaseClass, VaadinConfig vaadinConfig) throws VaadinConfigurationException { - return new DefaultDeploymentConfiguration(systemPropertyBaseClass, + return new DefaultDeploymentConfiguration( + ApplicationConfiguration.get(vaadinConfig.getVaadinContext()), + systemPropertyBaseClass, createInitParameters(systemPropertyBaseClass, vaadinConfig)); } @@ -107,10 +98,12 @@ public static DeploymentConfiguration createDeploymentConfiguration( * @throws VaadinConfigurationException * thrown if property construction fails */ - public static DeploymentConfiguration createPropertyDeploymentConfiguration( + public DeploymentConfiguration createPropertyDeploymentConfiguration( Class systemPropertyBaseClass, VaadinConfig vaadinConfig) throws VaadinConfigurationException { - return new PropertyDeploymentConfiguration(systemPropertyBaseClass, + return new PropertyDeploymentConfiguration( + ApplicationConfiguration.get(vaadinConfig.getVaadinContext()), + systemPropertyBaseClass, createInitParameters(systemPropertyBaseClass, vaadinConfig)); } @@ -126,22 +119,12 @@ public static DeploymentConfiguration createPropertyDeploymentConfiguration( * @throws VaadinConfigurationException * thrown if property construction fails */ - protected static Properties createInitParameters( - Class systemPropertyBaseClass, VaadinConfig vaadinConfig) - throws VaadinConfigurationException { + protected Properties createInitParameters(Class systemPropertyBaseClass, + VaadinConfig vaadinConfig) throws VaadinConfigurationException { Properties initParameters = new Properties(); readUiFromEnclosingClass(systemPropertyBaseClass, initParameters); readConfigurationAnnotation(systemPropertyBaseClass, initParameters); - // TODO : will be removed in futher commits - // Read default parameters from server.xml - final VaadinContext context = vaadinConfig.getVaadinContext(); - for (final Enumeration e = context.getContextParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - initParameters.setProperty(name, context.getContextParameter(name)); - } - // Override with application config from web.xml for (final Enumeration e = vaadinConfig .getConfigParameterNames(); e.hasMoreElements();) { @@ -155,19 +138,17 @@ protected static Properties createInitParameters( return initParameters; } - private static void readBuildInfo(Class systemPropertyBaseClass, + private void readBuildInfo(Class systemPropertyBaseClass, Properties initParameters, VaadinContext context) { - String json = getTokenFileContents(systemPropertyBaseClass, - initParameters, context); + String json = getTokenFileContents(initParameters); // Read the json and set the appropriate system properties if not // already set. if (json != null) { JsonObject buildInfo = JsonUtil.parse(json); - // TODO : will be rewritten properly without extra instantiation - Map params = new AbstractConfigurationFactory() - .getConfigParametersUsingTokenData(buildInfo); - initParameters.putAll(params); + Map properties = getInitParametersUsingTokenData( + buildInfo); + initParameters.putAll(properties); FallbackChunk fallbackChunk = FrontendUtils .readFallbackChunk(buildInfo); @@ -177,18 +158,12 @@ private static void readBuildInfo(Class systemPropertyBaseClass, } } - private static String getTokenFileContents(Class systemPropertyBaseClass, - Properties initParameters, VaadinContext context) { - String json = null; + private static String getTokenFileContents(Properties initParameters) { try { - json = getResourceFromFile(initParameters); - if (json == null) { - json = getTokenFileFromClassloader(context); - } + return getResourceFromFile(initParameters); } catch (IOException e) { throw new UncheckedIOException(e); } - return json; } private static String getResourceFromFile(Properties initParameters) @@ -206,132 +181,6 @@ private static String getResourceFromFile(Properties initParameters) return json; } - /** - * Gets token file from the classpath using the provided {@code context}. - *

- * The {@code contextClass} may be a class which is defined in the Web - * Application module/bundle and in this case it may be used to get Web - * Application resources. Also a {@link VaadinContext} {@code context} - * instance may be used to get a context of the Web Application (since the - * {@code contextClass} may be a class not from Web Application module). In - * WAR case it doesn't matter which class is used to get the resources (Web - * Application classes or e.g. "flow-server" classes) since they are loaded - * by the same {@link ClassLoader}. But in OSGi "flow-server" module classes - * can't be used to get Web Application resources since they are in - * different bundles. - * - * @param context - * a VaadinContext which may provide information how to get token - * file for the web application - * @return the token file content - * @throws IOException - * if I/O fails during access to the token file - */ - private static String getTokenFileFromClassloader(VaadinContext context) - throws IOException { - String tokenResource = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; - - Lookup lookup = context.getAttribute(Lookup.class); - ResourceProvider resourceProvider = lookup - .lookup(ResourceProvider.class); - - List resources = resourceProvider - .getApplicationResources(tokenResource); - - // Accept resource that doesn't contain - // 'jar!/META-INF/Vaadin/config/flow-build-info.json' - URL resource = resources.stream() - .filter(url -> !url.getPath().endsWith("jar!/" + tokenResource)) - .findFirst().orElse(null); - if (resource == null && !resources.isEmpty()) { - // For no non jar build info, in production mode check for - // webpack.generated.json if it's in a jar then accept - // single jar flow-build-info. - return getPossibleJarResource(context, resources); - } - return resource == null ? null - : FrontendUtils.streamToString(resource.openStream()); - - } - - /** - * Check if the webpack.generated.js resources is inside 2 jars - * (flow-server.jar and application.jar) if this is the case then we can - * accept a build info file from inside jar with a single jar in the path. - *

- * Else we will accept any flow-build-info and log a warning that it may not - * be the correct file, but it's the best we could find. - */ - private static String getPossibleJarResource(VaadinContext context, - List resources) throws IOException { - Objects.requireNonNull(resources); - - Lookup lookup = context.getAttribute(Lookup.class); - ResourceProvider resourceProvider = lookup - .lookup(ResourceProvider.class); - - assert !resources - .isEmpty() : "Possible jar resource requires resources to be available."; - - URL webpackGenerated = resourceProvider - .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); - - // If jar!/ exists 2 times for webpack.generated.json then we are - // running from a jar - if (webpackGenerated != null - && countInstances(webpackGenerated.getPath(), "jar!/") >= 2) { - for (URL resource : resources) { - // As we now know that we are running from a jar we can accept a - // build info with a single jar in the path - if (countInstances(resource.getPath(), "jar!/") == 1) { - return FrontendUtils.streamToString(resource.openStream()); - } - } - } - URL firstResource = resources.get(0); - if (resources.size() > 1) { - String warningMessage = String.format( - "Unable to fully determine correct flow-build-info.%n" - + "Accepting file '%s' first match of '%s' possible.%n" - + "Please verify flow-build-info file content.", - firstResource.getPath(), resources.size()); - logger.warn(warningMessage); - } else { - String debugMessage = String.format( - "Unable to fully determine correct flow-build-info.%n" - + "Accepting file '%s'", - firstResource.getPath()); - logger.debug(debugMessage); - } - return FrontendUtils.streamToString(firstResource.openStream()); - } - - private static int countInstances(String input, String value) { - return input.split(value, -1).length - 1; - } - - /** - * Verify that given folder actually exists on the system if we are not in - * production mode. - *

- * If folder doesn't exist throw IllegalStateException saying that this - * should probably be a production mode build. - * - * @param initParameters - * deployment init parameters - * @param folder - * folder to check exists - */ - private static void verifyFolderExists(Properties initParameters, - String folder) { - Boolean productionMode = Boolean.parseBoolean(initParameters - .getProperty(SERVLET_PARAMETER_PRODUCTION_MODE, "false")); - if (!productionMode && !new File(folder).exists()) { - String message = String.format(DEV_FOLDER_MISSING_MESSAGE, folder); - throw new IllegalStateException(message); - } - } - private static void readUiFromEnclosingClass( Class systemPropertyBaseClass, Properties initParameters) { Class enclosingClass = systemPropertyBaseClass.getEnclosingClass(); @@ -396,4 +245,4 @@ private static void readConfigurationAnnotation( } } } -} +} \ No newline at end of file diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java index a871114bbea..28eba6c22ec 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java @@ -52,6 +52,7 @@ import com.vaadin.flow.server.communication.StreamRequestHandler; import com.vaadin.flow.server.frontend.FrontendTools; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static com.vaadin.flow.server.Constants.VAADIN_MAPPING; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DEVMODE_WEBPACK_ERROR_PATTERN; @@ -200,8 +201,8 @@ public static DevModeHandler start(Lookup lookup, File npmFolder, */ public static DevModeHandler start(int runningPort, Lookup lookup, File npmFolder, CompletableFuture waitFor) { - DeploymentConfiguration configuration = lookup - .lookup(DeploymentConfiguration.class); + ApplicationConfiguration configuration = lookup + .lookup(ApplicationConfiguration.class); if (configuration.isProductionMode() || !configuration.enableDevServer()) { return null; diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java index e7fa4ff1680..9fb5a05e373 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java @@ -19,7 +19,6 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; import javax.servlet.annotation.HandlesTypes; import javax.servlet.annotation.WebListener; @@ -37,7 +36,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; @@ -66,7 +64,6 @@ import com.vaadin.flow.component.dependency.NpmPackage; import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.router.HasErrorParameter; import com.vaadin.flow.router.Route; import com.vaadin.flow.server.Constants; @@ -85,7 +82,6 @@ import com.vaadin.flow.server.frontend.NodeTasks.Builder; import com.vaadin.flow.server.frontend.scanner.ClassFinder; import com.vaadin.flow.server.frontend.scanner.ClassFinder.DefaultClassFinder; -import com.vaadin.flow.server.startup.ServletDeployer.StubServletConfig; import com.vaadin.flow.theme.NoTheme; import com.vaadin.flow.theme.Theme; @@ -203,28 +199,7 @@ private static Set calculateApplicableClassNames() { @Override public void process(Set> classes, ServletContext context) throws ServletException { - Collection registrations = context - .getServletRegistrations().values(); - - ServletRegistration vaadinServletRegistration = null; - for (ServletRegistration registration : registrations) { - if (registration.getClassName() != null - && isVaadinServletSubClass(registration.getClassName())) { - vaadinServletRegistration = registration; - break; - } - } - - DeploymentConfiguration config; - if (vaadinServletRegistration != null) { - config = StubServletConfig.createDeploymentConfiguration(context, - vaadinServletRegistration, VaadinServlet.class); - } else { - config = StubServletConfig.createDeploymentConfiguration(context, - VaadinServlet.class); - } - - initDevModeHandler(classes, context, config); + initDevModeHandler(classes, context); setDevModeStarted(context); } @@ -260,8 +235,11 @@ private void setDevModeStarted(ServletContext context) { * if dev mode can't be initialized */ public static void initDevModeHandler(Set> classes, - ServletContext context, DeploymentConfiguration config) - throws ServletException { + ServletContext context) throws ServletException { + VaadinContext vaadinContext = new VaadinServletContext(context); + + ApplicationConfiguration config = ApplicationConfiguration + .get(vaadinContext); if (config.isProductionMode()) { log().debug("Skipping DEV MODE because PRODUCTION MODE is set."); return; @@ -286,13 +264,14 @@ public static void initDevModeHandler(Set> classes, File flowResourcesFolder = new File(baseDir, DEFAULT_FLOW_RESOURCES_FOLDER); - VaadinContext vaadinContext = new VaadinServletContext(context); - Lookup lookupFromServletConetext = new VaadinServletContext(context).getAttribute(Lookup.class); - Lookup lookupForClassFinder = Lookup.of(new DevModeClassFinder(classes), ClassFinder.class); - Lookup lookup = Lookup.compose(lookupForClassFinder, lookupFromServletConetext); - Builder builder = new NodeTasks.Builder(lookup, - new File(baseDir), new File(generatedDir), - new File(frontendFolder)); + Lookup lookupFromServletConetext = new VaadinServletContext(context) + .getAttribute(Lookup.class); + Lookup lookupForClassFinder = Lookup.of(new DevModeClassFinder(classes), + ClassFinder.class); + Lookup lookup = Lookup.compose(lookupForClassFinder, + lookupFromServletConetext); + Builder builder = new NodeTasks.Builder(lookup, new File(baseDir), + new File(generatedDir), new File(frontendFolder)); log().info("Starting dev-mode updaters in {} folder.", builder.npmFolder); @@ -397,7 +376,7 @@ public static void initDevModeHandler(Set> classes, DevModeHandler.start( Lookup.compose(lookup, - Lookup.of(config, DeploymentConfiguration.class)), + Lookup.of(config, ApplicationConfiguration.class)), builder.npmFolder, nodeTasksFuture); } @@ -411,9 +390,10 @@ private static boolean isEndpointServiceAvailable(Lookup lookup) { /** * Shows whether {@link DevModeHandler} has been already started or not. * - * @param servletContext The servlet context, not null - * @return true if {@link DevModeHandler} has already been started, - * false - otherwise + * @param servletContext + * The servlet context, not null + * @return true if {@link DevModeHandler} has already been + * started, false - otherwise */ public static boolean isDevModeAlreadyStarted( ServletContext servletContext) { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java index 2b3e2526172..f772b713dcd 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java @@ -21,6 +21,7 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRegistration; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -28,6 +29,9 @@ import java.util.Map; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.router.Route; import com.vaadin.flow.server.DeploymentConfigurationFactory; @@ -43,8 +47,6 @@ import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.frontend.FrontendUtils; import com.vaadin.flow.server.webcomponent.WebComponentConfigurationRegistry; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Context listener that automatically registers Vaadin servlets. @@ -65,8 +67,8 @@ *

* In addition to the rules above, a servlet won't be registered, if any servlet * had been mapped to the same path already or if - * {@link InitParameters#DISABLE_AUTOMATIC_SERVLET_REGISTRATION} - * system property is set to {@code true}. + * {@link InitParameters#DISABLE_AUTOMATIC_SERVLET_REGISTRATION} system property + * is set to {@code true}. * * @author Vaadin Ltd * @see VaadinServletConfiguration#disableAutomaticServletRegistration() @@ -126,7 +128,7 @@ public String getConfigParameter(String name) { /** * Default ServletConfig implementation. */ - public static class StubServletConfig implements ServletConfig { + private static class StubServletConfig implements ServletConfig { private final ServletContext context; private final ServletRegistration registration; @@ -261,7 +263,8 @@ private void logServletCreation(VaadinServletCreation servletCreation, } /** - * Prints to sysout a notification to the user that the application has been deployed. + * Prints to sysout a notification to the user that the application has been + * deployed. *

* This method is public so that it can be called in add-ons that map * servlet automatically but don't use this class for that. diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java index 971c48d8516..cbf0a1bdaca 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java @@ -19,14 +19,13 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; import javax.servlet.annotation.HandlesTypes; import javax.servlet.annotation.WebListener; + import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -47,9 +46,7 @@ import com.vaadin.flow.server.InvalidApplicationConfigurationException; import com.vaadin.flow.server.PWA; import com.vaadin.flow.server.PageConfigurator; -import com.vaadin.flow.server.VaadinServlet; import com.vaadin.flow.server.VaadinServletContext; -import com.vaadin.flow.server.startup.ServletDeployer.StubServletConfig; import com.vaadin.flow.theme.NoTheme; import com.vaadin.flow.theme.Theme; @@ -79,18 +76,7 @@ public class VaadinAppShellInitializer @Override public void process(Set> classes, ServletContext context) throws ServletException { - - Collection registrations = context - .getServletRegistrations().values(); - if (registrations.isEmpty()) { - return; - } - - DeploymentConfiguration config = StubServletConfig - .createDeploymentConfiguration(context, - registrations.iterator().next(), VaadinServlet.class); - - init(classes, context, config); + init(classes, context); } /** @@ -105,8 +91,9 @@ public void process(Set> classes, ServletContext context) * the vaadin configuration for the application. */ @SuppressWarnings("unchecked") - public static void init(Set> classes, ServletContext context, - DeploymentConfiguration config) { + public static void init(Set> classes, ServletContext context) { + ApplicationConfiguration config = ApplicationConfiguration + .get(new VaadinServletContext(context)); if (config.useV14Bootstrap()) { return; From e13980f4f347de7f04ca01a587a9f248775f5df6 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 14 Dec 2020 13:37:22 +0300 Subject: [PATCH 03/32] chore: implement deployment configs being based on parent app config --- .../server/AbstractPropertyConfiguration.java | 36 ++++--- .../DefaultDeploymentConfiguration.java | 20 +++- .../PropertyDeploymentConfiguration.java | 69 ++++++++++++-- .../com/vaadin/flow/server/VaadinServlet.java | 10 +- .../flow/server/startup/ServletDeployer.java | 4 +- .../flow/server/CustomUIClassLoaderTest.java | 8 +- .../DefaultDeploymentConfigurationTest.java | 28 ++++-- .../DeploymentConfigurationFactoryTest.java | 27 +++--- .../PushAtmosphereHandlerTest.java | 13 ++- .../communication/UidlRequestHandlerTest.java | 94 ++++++++----------- .../servlet/ApplicationRunnerServlet.java | 4 + 11 files changed, 199 insertions(+), 114 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java index 0914f4e30c9..f5f9265349c 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractPropertyConfiguration.java @@ -16,6 +16,7 @@ package com.vaadin.flow.server; import java.util.Collections; +import java.util.Locale; import java.util.Map; import java.util.function.Function; @@ -82,17 +83,7 @@ public boolean getBooleanProperty(String name, boolean defaultValue) { * @return String value or null if not found */ public String getApplicationProperty(String parameterName) { - - String val = properties.get(parameterName); - if (val != null) { - return val; - } - - // Try lower case application properties for backward compatibility - // with 3.0.2 and earlier - val = properties.get(parameterName.toLowerCase()); - - return val; + return getApplicationProperty(getProperties()::get, parameterName); } /** @@ -150,4 +141,27 @@ protected String getSystemProperty(String parameterName) { return System.getProperty(VAADIN_PREFIX + parameterName); } + /** + * Gets application property value using the {@code valueProvider}. + * + * @param valueProvider + * a value provider for the property + * @param propertyName + * the name or the parameter. + * @return String value or null if not found + */ + protected String getApplicationProperty( + Function valueProvider, String propertyName) { + String val = valueProvider.apply(propertyName); + if (val != null) { + return val; + } + + // Try lower case application properties for backward compatibility with + // 3.0.2 and earlier + val = valueProvider.apply(propertyName.toLowerCase(Locale.ENGLISH)); + + return val; + } + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java index a94ab8229ed..5e646f18006 100755 --- a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java @@ -132,7 +132,7 @@ public class DefaultDeploymentConfiguration */ public DefaultDeploymentConfiguration(ApplicationConfiguration parentConfig, Class systemPropertyBaseClass, Properties initParameters) { - super(systemPropertyBaseClass, initParameters); + super(parentConfig, systemPropertyBaseClass, initParameters); boolean log = logging.getAndSet(false); @@ -289,8 +289,12 @@ public String getPushURL() { * Log a warning if Vaadin is not running in production mode. */ private void checkProductionMode(boolean log) { - productionMode = getBooleanProperty( - InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, false); + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE)) { + productionMode = getBooleanProperty( + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, false); + } else { + productionMode = getParentConfiguration().isProductionMode(); + } if (log) { if (productionMode) { info.add("Vaadin is running in production mode."); @@ -308,8 +312,13 @@ private void checkProductionMode(boolean log) { * Log a message about the bootstrapping being used. */ private void checkV14Bootsrapping(boolean log) { - useDeprecatedV14Bootstrapping = getBooleanProperty( - InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, false); + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP)) { + useDeprecatedV14Bootstrapping = getBooleanProperty( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, false); + } else { + useDeprecatedV14Bootstrapping = getParentConfiguration() + .useV14Bootstrap(); + } if (log) { if (useDeprecatedV14Bootstrapping) { warnings.add(WARNING_V14_BOOTSTRAP); @@ -451,4 +460,5 @@ private void checkSendUrlsAsParameters() { InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, DEFAULT_SEND_URLS_AS_PARAMETERS); } + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index 6281cf30136..f6e717f2bf4 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -32,6 +32,7 @@ import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REQUEST_TIMING; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SYNC_ID_CHECK; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; /** * The property handling implementation of {@link DeploymentConfiguration} based @@ -46,6 +47,8 @@ public class PropertyDeploymentConfiguration private final Properties initialParameters; + private final ApplicationConfiguration parentConfig; + /** * Create a new property deployment configuration instance. * @@ -62,6 +65,7 @@ public PropertyDeploymentConfiguration( ApplicationConfiguration parentConfig, Class systemPropertyBaseClass, Properties initParameters) { super(filterStringProperties(initParameters)); + this.parentConfig = parentConfig; initialParameters = initParameters; this.systemPropertyBaseClass = systemPropertyBaseClass; } @@ -118,22 +122,38 @@ protected String getSystemProperty(String parameterName) { */ @Override public String getApplicationProperty(String parameterName) { - - String val = getProperties().get(parameterName); - if (val != null) { - return val; + String val = getApplicationProperty(getProperties()::get, + parameterName); + if (val == null) { + val = getApplicationProperty( + parentConfig.getStringProperty(parameterName, null)); } - - // Try lower case application properties for backward compatibility with - // 3.0.2 and earlier - val = getProperties().get(parameterName.toLowerCase()); - return val; } @Override public boolean isProductionMode() { - return getBooleanProperty(SERVLET_PARAMETER_PRODUCTION_MODE, false); + return getBooleanProperty(SERVLET_PARAMETER_PRODUCTION_MODE, + parentConfig.isProductionMode()); + } + + @Override + public boolean enableDevServer() { + return getBooleanProperty( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, + parentConfig.enableDevServer()); + } + + @Override + public boolean useV14Bootstrap() { + return getBooleanProperty(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, + parentConfig.useV14Bootstrap()); + } + + @Override + public boolean isPnpmEnabled() { + return getBooleanProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + parentConfig.isPnpmEnabled()); } @Override @@ -209,6 +229,34 @@ && getBooleanProperty( && enableDevServer(); // gizmo excluded from prod bundle } + /** + * Checks whether the given {@code property} is the property explicitly set + * in this deployment configuration (not in it's parent config). + *

+ * The deployment configuration consists of properties defined in the + * configuration itself and properties which are coming from the application + * configuration. The properties which are defined in the deployment + * configuration itself (own properties) should take precedence: their + * values should override the parent config properties values. + * + * @param property + * a property name + * @return whether the {@code property} is explicitly set in the + * configuration + */ + protected boolean isOwnProperty(String property) { + return getApplicationProperty(getProperties()::get, property) != null; + } + + /** + * Returns parent application configuration; + * + * @return the parent config + */ + protected ApplicationConfiguration getParentConfiguration() { + return parentConfig; + } + private static Map filterStringProperties( Properties properties) { Map result = new HashMap<>(); @@ -222,4 +270,5 @@ private static Map filterStringProperties( } return result; } + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java index eb03ee27b7d..26fb2c36fd1 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java @@ -34,6 +34,7 @@ import com.vaadin.flow.internal.CurrentInstance; import com.vaadin.flow.internal.VaadinContextInitializer; import com.vaadin.flow.server.HandlerHelper.RequestType; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.shared.JsonConstants; /** @@ -181,8 +182,9 @@ public static VaadinServlet getCurrent() { protected DeploymentConfiguration createDeploymentConfiguration() throws ServletException { try { - return createDeploymentConfiguration(DeploymentConfigurationFactory - .createInitParameters(getClass(), + return createDeploymentConfiguration( + new DeploymentConfigurationFactory().createInitParameters( + getClass(), new VaadinServletConfig(getServletConfig()))); } catch (VaadinConfigurationException e) { throw new ServletException( @@ -201,7 +203,9 @@ protected DeploymentConfiguration createDeploymentConfiguration() */ protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { - return new DefaultDeploymentConfiguration(getClass(), initParameters); + return new DefaultDeploymentConfiguration( + ApplicationConfiguration.get(getService().getContext()), + getClass(), initParameters); } /** diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java index f772b713dcd..a9bd8410996 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java @@ -184,7 +184,7 @@ public static DeploymentConfiguration createDeploymentConfiguration( try { ServletConfig servletConfig = new StubServletConfig(context, registration); - return DeploymentConfigurationFactory + return new DeploymentConfigurationFactory() .createPropertyDeploymentConfiguration(servletClass, new VaadinServletConfig(servletConfig)); } catch (VaadinConfigurationException e) { @@ -206,7 +206,7 @@ public static DeploymentConfiguration createDeploymentConfiguration( public static DeploymentConfiguration createDeploymentConfiguration( ServletContext context, Class servletClass) { try { - return DeploymentConfigurationFactory + return new DeploymentConfigurationFactory() .createPropertyDeploymentConfiguration(servletClass, new VaadinServletContextConfig(context)); } catch (VaadinConfigurationException e) { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java b/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java index 01a32e59791..a27e42d4969 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java @@ -6,9 +6,11 @@ import junit.framework.TestCase; import org.easymock.EasyMock; +import org.mockito.Mockito; import com.vaadin.flow.component.UI; import com.vaadin.flow.function.DeploymentConfiguration; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.tests.util.AlwaysLockedVaadinSession; public class CustomUIClassLoaderTest extends TestCase { @@ -59,8 +61,10 @@ public void testWithDefaultClassLoader() throws Exception { private static DeploymentConfiguration createConfigurationMock() { Properties properties = new Properties(); properties.put(InitParameters.UI_PARAMETER, MyUI.class.getName()); - return new DefaultDeploymentConfiguration(CustomUIClassLoaderTest.class, - properties); + ApplicationConfiguration congif = Mockito + .mock(ApplicationConfiguration.class); + return new DefaultDeploymentConfiguration(congif, + CustomUIClassLoaderTest.class, properties); } private static VaadinRequest createRequestMock(ClassLoader classloader) { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java index 9872205cc1e..989ce1044ac 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java @@ -18,6 +18,9 @@ import java.util.Properties; import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; @@ -41,8 +44,10 @@ public void testGetSystemPropertyForDefaultPackage() String prop = "prop"; System.setProperty(prop, value); Properties initParameters = new Properties(); + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); DefaultDeploymentConfiguration config = new DefaultDeploymentConfiguration( - clazz, initParameters); + appConfig, clazz, initParameters); assertEquals(value, config.getSystemProperty(prop)); } @@ -55,8 +60,11 @@ public void testGetSystemProperty() throws ClassNotFoundException { + '.' + prop, value); Properties initParameters = new Properties(); + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); DefaultDeploymentConfiguration config = new DefaultDeploymentConfiguration( - DefaultDeploymentConfigurationTest.class, initParameters); + appConfig, DefaultDeploymentConfigurationTest.class, + initParameters); assertEquals(value, config.getSystemProperty(prop)); } @@ -64,7 +72,8 @@ public void testGetSystemProperty() throws ClassNotFoundException { public void booleanValueReadIgnoreTheCase_true() { Properties initParameters = new Properties(); initParameters.setProperty( - InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, "tRUe"); + InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, + "tRUe"); DefaultDeploymentConfiguration config = createDeploymentConfig( initParameters); @@ -77,7 +86,8 @@ public void booleanValueReadIgnoreTheCase_true() { public void booleanValueReadIgnoreTheCase_false() { Properties initParameters = new Properties(); initParameters.setProperty( - InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, "FaLsE"); + InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, + "FaLsE"); DefaultDeploymentConfiguration config = createDeploymentConfig( initParameters); @@ -112,7 +122,9 @@ public void booleanValueRead_exceptionOnNonBooleanValue() { private DefaultDeploymentConfiguration createDeploymentConfig( Properties initParameters) { - return new DefaultDeploymentConfiguration( + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + return new DefaultDeploymentConfiguration(appConfig, DefaultDeploymentConfigurationTest.class, initParameters); } @@ -127,7 +139,8 @@ public void defaultPushUrl() { @Test public void pushUrl() { Properties initParameters = new Properties(); - initParameters.setProperty(InitParameters.SERVLET_PARAMETER_PUSH_URL, "foo"); + initParameters.setProperty(InitParameters.SERVLET_PARAMETER_PUSH_URL, + "foo"); DefaultDeploymentConfiguration config = createDeploymentConfig( initParameters); @@ -149,7 +162,8 @@ public void maxMessageSuspendTimeout_validValue_accepted() { public void maxMessageSuspendTimeout_invalidValue_defaultValue() { Properties initParameters = new Properties(); initParameters.setProperty( - InitParameters.SERVLET_PARAMETER_MAX_MESSAGE_SUSPEND_TIMEOUT, "kk"); + InitParameters.SERVLET_PARAMETER_MAX_MESSAGE_SUSPEND_TIMEOUT, + "kk"); DefaultDeploymentConfiguration config = createDeploymentConfig( initParameters); assertEquals(5000, config.getMaxMessageSuspendTimeout()); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 86a509a57f8..755ad95e44f 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -40,10 +40,10 @@ import com.vaadin.flow.server.frontend.FrontendUtils; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; -import static com.vaadin.flow.server.DeploymentConfigurationFactory.DEV_FOLDER_MISSING_MESSAGE; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_TOKEN_FILE; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; +import static com.vaadin.flow.server.startup.AbstractConfigurationFactory.DEV_FOLDER_MISSING_MESSAGE; import static java.util.Collections.emptyMap; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.expect; @@ -100,7 +100,7 @@ public void servletWithEnclosingUI_hasItsNameInConfig() throws Exception { Map servletConfigParams = new HashMap<>( new HashMap<>(defaultServletParams)); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock(servletConfigParams, Collections.singletonMap(PARAM_TOKEN_FILE, @@ -124,7 +124,7 @@ public void servletWithNoEnclosingUI_hasDefaultUiInConfig() Map servletConfigParams = new HashMap<>( defaultServletParams); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock( servletConfigParams, emptyMap())); @@ -144,7 +144,7 @@ public void vaadinServletConfigurationRead() throws Exception { Map servletConfigParams = new HashMap<>( defaultServletParams); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock( servletConfigParams, emptyMap())); @@ -172,7 +172,7 @@ public void servletConfigParametersOverrideVaadinParameters() InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, Integer.toString(overridingHeartbeatIntervalValue)); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock( servletConfigParams, emptyMap())); @@ -201,7 +201,7 @@ public void servletContextParametersOverrideVaadinParameters() InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, Integer.toString(overridingHeartbeatIntervalValue)); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock( emptyMap(), servletContextParams)); @@ -240,7 +240,7 @@ public void servletConfigParametersOverrideServletContextParameters() InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, Integer.toString(servletContextHeartbeatIntervalValue)); - DeploymentConfiguration config = DeploymentConfigurationFactory + DeploymentConfiguration config = new DeploymentConfigurationFactory() .createDeploymentConfiguration(servlet, createVaadinConfigMock( servletConfigParams, servletContextParams)); @@ -264,7 +264,7 @@ public void shouldNotThrow_noTokenFile_correctWebPackConfigExists() FrontendUtils.WEBPACK_CONFIG); FileUtils.writeLines(webPack, Arrays.asList("./webpack.generated.js")); - DeploymentConfigurationFactory.createDeploymentConfiguration( + new DeploymentConfigurationFactory().createDeploymentConfiguration( VaadinServlet.class, createVaadinConfigMock(map, emptyMap())); } @@ -437,7 +437,7 @@ public void createInitParameters_fallbackChunkObjectIsInInitParams() Mockito.when(context.getInitParameter(FrontendUtils.PARAM_TOKEN_FILE)) .thenReturn(tokenFile.getPath()); - Properties properties = DeploymentConfigurationFactory + Properties properties = new DeploymentConfigurationFactory() .createInitParameters(Object.class, new VaadinServletConfig(config)); @@ -482,7 +482,7 @@ public void createInitParameters_readTokenFileFromContext() ResourceProvider resourceProvider = mockResourceProvider(config, context); - DeploymentConfigurationFactory.createInitParameters( + new DeploymentConfigurationFactory().createInitParameters( DeploymentConfigurationFactoryTest.class, config); Mockito.verify(resourceProvider) @@ -519,7 +519,7 @@ protected URLConnection openConnection(URL u) throws IOException { .getApplicationResource(FrontendUtils.WEBPACK_GENERATED)) .thenReturn(tmpFile.toURI().toURL()); - DeploymentConfigurationFactory.createInitParameters( + new DeploymentConfigurationFactory().createInitParameters( DeploymentConfigurationFactoryTest.class, config); Mockito.verify(resourceProvider) @@ -557,8 +557,9 @@ public void createInitParameters_initParamtersAreSet_tokenDevModePropertiesAreNo private DeploymentConfiguration createConfig(Map map) throws Exception { - return DeploymentConfigurationFactory.createDeploymentConfiguration( - VaadinServlet.class, createVaadinConfigMock(map, emptyMap())); + return new DeploymentConfigurationFactory() + .createDeploymentConfiguration(VaadinServlet.class, + createVaadinConfigMock(map, emptyMap())); } private VaadinConfig createVaadinConfigMock( diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java index df5c4fbf412..ebc61ec692c 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java @@ -21,8 +21,6 @@ import java.io.PrintWriter; import java.util.Properties; -import com.vaadin.flow.server.DefaultDeploymentConfiguration; -import com.vaadin.flow.server.VaadinServletService; import org.atmosphere.cpr.AtmosphereRequest; import org.atmosphere.cpr.AtmosphereResource; import org.atmosphere.cpr.AtmosphereResponse; @@ -31,6 +29,10 @@ import org.junit.Test; import org.mockito.Mockito; +import com.vaadin.flow.server.DefaultDeploymentConfiguration; +import com.vaadin.flow.server.VaadinServletService; +import com.vaadin.flow.server.startup.ApplicationConfiguration; + public class PushAtmosphereHandlerTest { private AtmosphereResource resource; @@ -52,8 +54,10 @@ public void setup() throws IOException { Mockito.when(resource.getRequest()).thenReturn(request); Mockito.when(resource.getResponse()).thenReturn(response); + ApplicationConfiguration congif = Mockito + .mock(ApplicationConfiguration.class); VaadinServletService service = new VaadinServletService(null, - new DefaultDeploymentConfiguration(getClass(), + new DefaultDeploymentConfiguration(congif, getClass(), new Properties())); PushHandler handler = new PushHandler(service); @@ -72,7 +76,8 @@ public void writeSessionExpiredAsyncPost() throws Exception { writeSessionExpiredAsync("POST"); } - private void writeSessionExpiredAsync(String httpMethod) throws IOException { + private void writeSessionExpiredAsync(String httpMethod) + throws IOException { Mockito.when(request.getMethod()).thenReturn(httpMethod); atmosphereHandler.onRequest(resource); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java index 20cc53636c3..9e59cc3f654 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java @@ -35,6 +35,7 @@ import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.shared.ApplicationConstants; import elemental.json.JsonObject; @@ -68,14 +69,14 @@ public void setup() throws IOException { @Test public void writeSessionExpired() throws Exception { - + ApplicationConfiguration congif = Mockito + .mock(ApplicationConfiguration.class); VaadinService service = new VaadinServletService(null, - new DefaultDeploymentConfiguration(getClass(), + new DefaultDeploymentConfiguration(congif, getClass(), new Properties())); when(request.getService()).thenReturn(service); - when(request - .getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER)) + when(request.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER)) .thenReturn(RequestType.UIDL.getIdentifier()); boolean result = handler.handleSessionExpired(request, response); @@ -113,7 +114,8 @@ public void writeSessionExpired_whenUINotFound() throws IOException { } @Test - public void should_not_modifyUidl_when_MPR_nonJavaScriptBootstrapUI() throws Exception { + public void should_not_modifyUidl_when_MPR_nonJavaScriptBootstrapUI() + throws Exception { JavaScriptBootstrapUI ui = null; UidlRequestHandler handler = spy(new UidlRequestHandler()); @@ -135,13 +137,13 @@ public void should_not_modifyUidl_when_MPR_nonJavaScriptBootstrapUI() throws Exc assertTrue(v7Uidl.contains("http://localhost:9998/#!away")); assertTrue(v7Uidl.contains("window.location.hash = '!away';")); - assertEquals( - "setTimeout(() => window.history.pushState(null, '', $0))", + assertEquals("setTimeout(() => window.history.pushState(null, '', $0))", uidl.getArray("execute").getArray(1).getString(1)); } @Test - public void should_modifyUidl_when_MPR_JavaScriptBootstrapUI() throws Exception { + public void should_modifyUidl_when_MPR_JavaScriptBootstrapUI() + throws Exception { JavaScriptBootstrapUI ui = mock(JavaScriptBootstrapUI.class); UidlRequestHandler handler = spy(new UidlRequestHandler()); @@ -182,7 +184,8 @@ public void should_changeURL_when_v7LocationProvided() throws Exception { } @Test - public void should_updateHash_when_v7LocationNotProvided() throws Exception { + public void should_updateHash_when_v7LocationNotProvided() + throws Exception { JavaScriptBootstrapUI ui = mock(JavaScriptBootstrapUI.class); UidlRequestHandler handler = spy(new UidlRequestHandler()); @@ -215,7 +218,6 @@ public void should_not_modify_non_MPR_Uidl() throws Exception { handler.writeUidl(ui, writer, false); - String expected = uidl.toJson(); String out = writer.toString(); @@ -227,53 +229,33 @@ public void should_not_modify_non_MPR_Uidl() throws Exception { } private JsonObject generateUidl(boolean withLocation, boolean withHash) { - JsonObject uidl = JsonUtil.parse( - "{" + - " \"syncId\": 3," + - " \"clientId\": 3," + - " \"changes\": []," + - " \"execute\": [" + - " [\"\", \"document.title = $0\"]," + - " [\"\", \"setTimeout(() => window.history.pushState(null, '', $0))\"]," + - " [[0, 16], \"___PLACE_FOR_V7_UIDL___\", \"$0.firstElementChild.setResponse($1)\"]," + - " [1,null,[0, 16], \"return (function() { this.$server['}p']($0, true, $1)}).apply($2)\"]" + - " ]," + - " \"timings\": []" + - "}"); - - String v7String = - "\"syncId\": 2," + - "\"clientId\": 2," + - "\"changes\": [" + - " [],[\"___PLACE_FOR_LOCATION_CHANGE___\"]" + - "]," + - "\"state\": {" + - "}," + - "\"types\": {" + - "}," + - "\"hierarchy\": {" + - "}," + - "\"rpc\": [" + - " [],[" + - " \"11\"," + - " \"com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc\"," + - " \"executeJavaScript\", [ \"___PLACE_FOR_HASH_RPC___\" ]" + - " ],[" + - " \"12\"," + - " \"com.example.FooRpc\"," + - " \"barMethod\", [{}, {}]" + - " ],[]" + - "]," + - "\"meta\": {}, \"resources\": {},\"typeMappings\": {},\"typeInheritanceMap\": {}, \"timings\": []"; - - String locationChange = - "\"change\", {\"pid\": \"0\"}, [\"0\", {\"id\": \"0\", \"location\": \"http://localhost:9998/#!away\"}]"; - - String hashRpc = - "window.location.hash = '!away';"; + JsonObject uidl = JsonUtil.parse("{" + " \"syncId\": 3," + + " \"clientId\": 3," + " \"changes\": []," + + " \"execute\": [" + " [\"\", \"document.title = $0\"]," + + " [\"\", \"setTimeout(() => window.history.pushState(null, '', $0))\"]," + + " [[0, 16], \"___PLACE_FOR_V7_UIDL___\", \"$0.firstElementChild.setResponse($1)\"]," + + " [1,null,[0, 16], \"return (function() { this.$server['}p']($0, true, $1)}).apply($2)\"]" + + " ]," + " \"timings\": []" + "}"); + + String v7String = "\"syncId\": 2," + "\"clientId\": 2," + + "\"changes\": [" + + " [],[\"___PLACE_FOR_LOCATION_CHANGE___\"]" + "]," + + "\"state\": {" + "}," + "\"types\": {" + "}," + + "\"hierarchy\": {" + "}," + "\"rpc\": [" + " [],[" + + " \"11\"," + + " \"com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc\"," + + " \"executeJavaScript\", [ \"___PLACE_FOR_HASH_RPC___\" ]" + + " ],[" + " \"12\"," + " \"com.example.FooRpc\"," + + " \"barMethod\", [{}, {}]" + " ],[]" + "]," + + "\"meta\": {}, \"resources\": {},\"typeMappings\": {},\"typeInheritanceMap\": {}, \"timings\": []"; + + String locationChange = "\"change\", {\"pid\": \"0\"}, [\"0\", {\"id\": \"0\", \"location\": \"http://localhost:9998/#!away\"}]"; + + String hashRpc = "window.location.hash = '!away';"; if (withLocation) { - v7String = v7String.replace("\"___PLACE_FOR_LOCATION_CHANGE___\"", locationChange); + v7String = v7String.replace("\"___PLACE_FOR_LOCATION_CHANGE___\"", + locationChange); } if (withHash) { v7String = v7String.replace("___PLACE_FOR_HASH_RPC___", hashRpc); @@ -283,6 +265,4 @@ private JsonObject generateUidl(boolean withLocation, boolean withHash) { return uidl; } - - } diff --git a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java index 577aaf16c96..0a0242a4f96 100644 --- a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java +++ b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java @@ -61,6 +61,7 @@ import com.vaadin.flow.server.VaadinServletRequest; import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.uitest.servlet.CustomDeploymentConfiguration.Conf; import elemental.json.JsonValue; @@ -245,6 +246,7 @@ protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { // Get the original configuration from the super class final DeploymentConfiguration originalConfiguration = new DefaultDeploymentConfiguration( + ApplicationConfiguration.get(getService().getContext()), getClass(), initParameters) { @Override public String getUIClassName() { @@ -399,6 +401,8 @@ private DeploymentConfiguration findDeploymentConfiguration( getApplicationRunnerApplicationClassName( request.get())); configuration = new DefaultDeploymentConfiguration( + ApplicationConfiguration + .get(getService().getContext()), servlet.getClass(), initParameters); } else { configuration = originalConfiguration; From d9fcad8a40e3f7a5c97f842ddfff9a6f0a92c6eb Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 14 Dec 2020 14:58:10 +0300 Subject: [PATCH 04/32] fix: fix javadoc params --- .../java/com/vaadin/flow/server/startup/DevModeInitializer.java | 2 -- .../vaadin/flow/server/startup/VaadinAppShellInitializer.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java index 9fb5a05e373..2e3a15e3b55 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DevModeInitializer.java @@ -228,8 +228,6 @@ private void setDevModeStarted(ServletContext context) { * classes to check for npm- and js modules * @param context * servlet context we are running in - * @param config - * deployment configuration * * @throws ServletException * if dev mode can't be initialized diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java index cbf0a1bdaca..9c54ef345c5 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java @@ -87,8 +87,6 @@ public void process(Set> classes, ServletContext context) * this class. * @param context * the servlet context. - * @param config - * the vaadin configuration for the application. */ @SuppressWarnings("unchecked") public static void init(Set> classes, ServletContext context) { From 7c8be8314be2dea05cff195d19469653c5ad4bb3 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 14 Dec 2020 15:25:14 +0300 Subject: [PATCH 05/32] fix: correct javadocs references --- .../flow/server/startup/VaadinAppShellInitializer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java index 9c54ef345c5..d344feac6eb 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/VaadinAppShellInitializer.java @@ -39,7 +39,6 @@ import com.vaadin.flow.component.page.Meta; import com.vaadin.flow.component.page.Push; import com.vaadin.flow.component.page.Viewport; -import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.server.AppShellRegistry; import com.vaadin.flow.server.Constants; @@ -171,7 +170,7 @@ public static void init(Set> classes, ServletContext context) { * scanning. * * @return list of annotations handled by - * {@link VaadinAppShellInitializer#init(Set, ServletContext, DeploymentConfiguration)} + * {@link VaadinAppShellInitializer#init(Set, ServletContext)} */ @SuppressWarnings("unchecked") public static List> getValidAnnotations() { @@ -187,7 +186,7 @@ public static List> getValidAnnotations() { * scanning. * * @return list of super classes handled by - * {@link VaadinAppShellInitializer#init(Set, ServletContext, DeploymentConfiguration)} + * {@link VaadinAppShellInitializer#init(Set, ServletContext)} */ public static List> getValidSupers() { return Arrays.stream(getHandledTypes()) From b1e65f4e9fe40aefa1668c0fcbbeaa6b05d37aa1 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Tue, 15 Dec 2020 12:31:50 +0300 Subject: [PATCH 06/32] test: use App config and adapt unit tests --- .../DeploymentConfigurationFactory.java | 105 +------ .../PropertyDeploymentConfiguration.java | 3 +- .../server/VaadinServletConfiguration.java | 124 -------- .../startup/AbstractConfigurationFactory.java | 35 +++ .../startup/ApplicationConfiguration.java | 9 + ...efaultApplicationConfigurationFactory.java | 30 +- .../server/startup/LookupInitializer.java | 34 ++- .../DeploymentConfigurationFactoryTest.java | 265 ++++++------------ ...ltApplicationConfigurationFactoryTest.java | 123 ++++++++ 9 files changed, 320 insertions(+), 408 deletions(-) delete mode 100644 flow-server/src/main/java/com/vaadin/flow/server/VaadinServletConfiguration.java create mode 100644 flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index c44355e6e89..14ae4a835b9 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -16,25 +16,16 @@ package com.vaadin.flow.server; -import java.io.File; -import java.io.IOException; import java.io.Serializable; -import java.io.UncheckedIOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.Map; -import java.util.Optional; import java.util.Properties; -import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.flow.component.UI; import com.vaadin.flow.function.DeploymentConfiguration; -import com.vaadin.flow.internal.AnnotationReader; import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; import com.vaadin.flow.server.startup.AbstractConfigurationFactory; @@ -43,8 +34,6 @@ import elemental.json.JsonObject; import elemental.json.impl.JsonUtil; -import static com.vaadin.flow.server.frontend.FrontendUtils.PARAM_TOKEN_FILE; - /** * Creates {@link DeploymentConfiguration} filled with all parameters specified * by the framework users. @@ -123,7 +112,6 @@ protected Properties createInitParameters(Class systemPropertyBaseClass, VaadinConfig vaadinConfig) throws VaadinConfigurationException { Properties initParameters = new Properties(); readUiFromEnclosingClass(systemPropertyBaseClass, initParameters); - readConfigurationAnnotation(systemPropertyBaseClass, initParameters); // Override with application config from web.xml for (final Enumeration e = vaadinConfig @@ -140,45 +128,27 @@ protected Properties createInitParameters(Class systemPropertyBaseClass, private void readBuildInfo(Class systemPropertyBaseClass, Properties initParameters, VaadinContext context) { - String json = getTokenFileContents(initParameters); + String json = getTokenFileContent(initParameters::getProperty); + + FallbackChunk fallbackChunk = null; // Read the json and set the appropriate system properties if not // already set. if (json != null) { JsonObject buildInfo = JsonUtil.parse(json); - Map properties = getInitParametersUsingTokenData( + Map properties = getConfigParametersUsingTokenData( buildInfo); initParameters.putAll(properties); - FallbackChunk fallbackChunk = FrontendUtils - .readFallbackChunk(buildInfo); - if (fallbackChunk != null) { - initParameters.put(FALLBACK_CHUNK, fallbackChunk); - } + fallbackChunk = FrontendUtils.readFallbackChunk(buildInfo); } - } - - private static String getTokenFileContents(Properties initParameters) { - try { - return getResourceFromFile(initParameters); - } catch (IOException e) { - throw new UncheckedIOException(e); + if (fallbackChunk == null) { + fallbackChunk = ApplicationConfiguration.get(context) + .getFallbackChunk(); } - } - - private static String getResourceFromFile(Properties initParameters) - throws IOException { - String json = null; - // token file location passed via init parameter property - String tokenLocation = initParameters.getProperty(PARAM_TOKEN_FILE); - if (tokenLocation != null) { - File tokenFile = new File(tokenLocation); - if (tokenFile != null && tokenFile.canRead()) { - json = FileUtils.readFileToString(tokenFile, - StandardCharsets.UTF_8); - } + if (fallbackChunk != null) { + initParameters.put(FALLBACK_CHUNK, fallbackChunk); } - return json; } private static void readUiFromEnclosingClass( @@ -192,57 +162,4 @@ private static void readUiFromEnclosingClass( } } - /** - * Read the VaadinServletConfiguration annotation for initialization name - * value pairs and add them to the initial properties object. - * - * @param systemPropertyBaseClass - * base class for constructing the configuration - * @param initParameters - * current initParameters object - * @throws VaadinConfigurationException - * exception thrown for failure in invoking method on - * configuration annotation - */ - private static void readConfigurationAnnotation( - Class systemPropertyBaseClass, Properties initParameters) - throws VaadinConfigurationException { - Optional optionalConfigAnnotation = AnnotationReader - .getAnnotationFor(systemPropertyBaseClass, - VaadinServletConfiguration.class); - - if (!optionalConfigAnnotation.isPresent()) { - return; - } - - VaadinServletConfiguration configuration = optionalConfigAnnotation - .get(); - Method[] methods = VaadinServletConfiguration.class - .getDeclaredMethods(); - for (Method method : methods) { - VaadinServletConfiguration.InitParameterName name = method - .getAnnotation( - VaadinServletConfiguration.InitParameterName.class); - assert name != null : "All methods declared in VaadinServletConfiguration should have a @InitParameterName annotation"; - - try { - Object value = method.invoke(configuration); - - String stringValue; - if (value instanceof Class) { - stringValue = ((Class) value).getName(); - } else { - stringValue = value.toString(); - } - - initParameters.setProperty(name.value(), stringValue); - } catch (IllegalAccessException | InvocationTargetException e) { - // This should never happen - throw new VaadinConfigurationException( - "Could not read @VaadinServletConfiguration value " - + method.getName(), - e); - } - } - } -} \ No newline at end of file +} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index f6e717f2bf4..59ac3086784 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -126,7 +126,8 @@ public String getApplicationProperty(String parameterName) { parameterName); if (val == null) { val = getApplicationProperty( - parentConfig.getStringProperty(parameterName, null)); + prop -> parentConfig.getStringProperty(prop, null), + parameterName); } return val; } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServletConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServletConfiguration.java deleted file mode 100644 index 846e729bf2d..00000000000 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServletConfiguration.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2000-2020 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.vaadin.flow.server; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.function.Function; - -import com.vaadin.flow.component.UI; -import com.vaadin.flow.function.DeploymentConfiguration; - -/** - * Configures subclasses of {@link VaadinServlet}. For a {@link VaadinServlet} - * class that has this annotation, the defined values are read during - * initialization and will be available using - * {@link DeploymentConfiguration#getApplicationOrSystemProperty(String, Object, Function)} - * as well as from specific methods in {@link DeploymentConfiguration}. Init - * params defined in web.xml or the @WebServlet - * annotation take precedence over values defined in this annotation. - * - * @deprecated Leftover from Vaadin Framework 8 where the developer typically - * defines their own servlet class. Starting from Flow 1.0, a - * servlet is automatically registered and this annotation serves - * very little purpose. - * - * @author Vaadin Ltd - * @since 1.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Deprecated -public @interface VaadinServletConfiguration { - /** - * Defines the init parameter name for methods in - * {@link VaadinServletConfiguration}. - * - * @author Vaadin Ltd - * @since 1.0 - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.METHOD) - @Documented - @interface InitParameterName { - /** - * The name of the init parameter that the annotated method controls. - * - * @return the parameter name - */ - String value(); - } - - /** - * Whether Vaadin is in production mode. - * - * @return true if in production mode, false otherwise. - * - * @see DeploymentConfiguration#isProductionMode() - */ - @InitParameterName(InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE) - boolean productionMode(); - - /** - * Gets the UI class to use for the servlet. - * - * @return the UI class - */ - @InitParameterName(InitParameters.UI_PARAMETER) - Class ui() default UI.class; - - /** - * The number of seconds between heartbeat requests of a UI, or a - * non-positive number if heartbeat is disabled. The default value is 300 - * seconds, i.e. 5 minutes. - * - * @return the time between heartbeats - * - * @see DeploymentConfiguration#getHeartbeatInterval() - */ - @InitParameterName(InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL) - int heartbeatInterval() default DefaultDeploymentConfiguration.DEFAULT_HEARTBEAT_INTERVAL; - - /** - * Whether a session should be closed when all its open UIs have been idle - * for longer than its configured maximum inactivity time. The default value - * is false. - * - * @return true if UIs and sessions receiving only heartbeat requests are - * eventually closed; false if heartbeat requests extend UI and - * session lifetime indefinitely - * - * @see DeploymentConfiguration#isCloseIdleSessions() - */ - @InitParameterName(InitParameters.SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS) - boolean closeIdleSessions() default DefaultDeploymentConfiguration.DEFAULT_CLOSE_IDLE_SESSIONS; - - /** - * Whether the framework should register automatic servlets for the - * application or not. The default value is false. - * - * @return true if no automatic servlet registration should be done - * - * @see DeploymentConfiguration#disableAutomaticServletRegistration() - */ - @InitParameterName(InitParameters.DISABLE_AUTOMATIC_SERVLET_REGISTRATION) - boolean disableAutomaticServletRegistration() default false; - -} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java index 1519f82c6da..9290490048c 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -16,9 +16,15 @@ package com.vaadin.flow.server.startup; import java.io.File; +import java.io.IOException; import java.io.Serializable; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.function.Function; + +import org.apache.commons.io.FileUtils; import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -171,6 +177,35 @@ protected void setDevModePropertiesUsingTokenData( } } + /** + * Gets the content of the token file with given {@code locationProvider}. + * + * @param locationProvider + * the token file location provider + * @return the token file location, may be {@code null} + * @throws IOException + * if an error occurs + */ + protected String getTokenFileContent( + Function locationProvider) { + String location = locationProvider + .apply(FrontendUtils.PARAM_TOKEN_FILE); + String json = null; + // token file location passed via init parameter property + try { + if (location != null) { + File tokenFile = new File(location); + if (tokenFile != null && tokenFile.canRead()) { + json = FileUtils.readFileToString(tokenFile, + StandardCharsets.UTF_8); + } + } + return json; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + /** * Verify that given folder actually exists on the system if we are not in * production mode. diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java index 5d972874d30..c22077b81f9 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ApplicationConfiguration.java @@ -23,6 +23,7 @@ import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.server.AbstractConfiguration; import com.vaadin.flow.server.VaadinContext; +import com.vaadin.flow.server.frontend.FallbackChunk; /** * Configuration on the application level. @@ -69,4 +70,12 @@ static ApplicationConfiguration get(VaadinContext context) { */ VaadinContext getContext(); + /** + * Gets a fallback chunk for the application or {@code null} if it's not + * available. + * + * @return the application fallback chunk, may be {@code null}. + */ + FallbackChunk getFallbackChunk(); + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java index 9bf5a9f707f..f6d37e0836e 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -32,6 +32,7 @@ import com.vaadin.flow.di.ResourceProvider; import com.vaadin.flow.server.AbstractPropertyConfiguration; import com.vaadin.flow.server.VaadinContext; +import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; import elemental.json.JsonObject; @@ -57,10 +58,13 @@ protected static class ApplicationConfigurationImpl extends private final VaadinContext context; + private final FallbackChunk fallbackChunk; + protected ApplicationConfigurationImpl(VaadinContext context, - Map properties) { + FallbackChunk fallbackChunk, Map properties) { super(properties); this.context = context; + this.fallbackChunk = fallbackChunk; } @Override @@ -78,6 +82,11 @@ public VaadinContext getContext() { return context; } + @Override + public FallbackChunk getFallbackChunk() { + return fallbackChunk; + } + } @Override @@ -88,15 +97,23 @@ public ApplicationConfiguration create(VaadinContext context) { final String name = e.nextElement(); props.put(name, context.getContextParameter(name)); } + JsonObject buildInfo = null; try { - JsonObject buildInfo = JsonUtil - .parse(getTokenFileFromClassloader(context)); - - props.putAll(getConfigParametersUsingTokenData(buildInfo)); + String content = getTokenFileContent(props::get); + if (content == null) { + content = getTokenFileFromClassloader(context); + } + buildInfo = content == null ? null : JsonUtil.parse(content); + if (buildInfo != null) { + props.putAll(getConfigParametersUsingTokenData(buildInfo)); + } } catch (IOException exception) { throw new UncheckedIOException(exception); } - return new ApplicationConfigurationImpl(context, props); + return new ApplicationConfigurationImpl(context, + buildInfo == null ? null + : FrontendUtils.readFallbackChunk(buildInfo), + props); } /** @@ -204,4 +221,5 @@ private Logger getLogger() { return LoggerFactory .getLogger(DefaultApplicationConfigurationFactory.class); } + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java index 867c25acf9d..2d3703c60dc 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java @@ -24,7 +24,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.Modifier; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -58,7 +57,8 @@ */ @HandlesTypes({ ResourceProvider.class, InstantiatorFactory.class, DeprecatedPolymerPublishedEventHandler.class, - EndpointGeneratorTaskFactory.class }) + EndpointGeneratorTaskFactory.class, + ApplicationConfigurationFactory.class }) public class LookupInitializer implements ClassLoaderAwareServletContainerInitializer { @@ -277,6 +277,9 @@ private void initStandardLookup(Set> classSet, for (Class serviceType : getServiceTypes()) { if (ResourceProvider.class.equals(serviceType)) { collectResourceProviders(classSet, services); + } + if (ApplicationConfigurationFactory.class.equals(serviceType)) { + collectApplicationConfigurationFactories(classSet, services); } else { collectSubclasses(serviceType, classSet, services); } @@ -310,6 +313,29 @@ private void collectResourceProviders(Set> classSet, } } + private void collectApplicationConfigurationFactories( + Set> classSet, + Map, Collection> services) { + Set> factories = filterSubClasses( + ApplicationConfigurationFactory.class, classSet); + factories.remove(DefaultApplicationConfigurationFactory.class); + if (factories.isEmpty()) { + services.put(ApplicationConfigurationFactory.class, + Collections.singletonList( + new DefaultApplicationConfigurationFactory())); + } else if (factories.size() > 1) { + throw new IllegalStateException(SEVERAL_IMPLS + + DefaultApplicationConfigurationFactory.class + .getSimpleName() + + SPI + classSet + ONE_IMPL_REQUIRED); + } else { + Class clazz = factories.iterator().next(); + services.put(DefaultApplicationConfigurationFactory.class, + Collections + .singletonList(ReflectTools.createInstance(clazz))); + } + } + private Set> filterResourceProviders(Set> classes) { Set> resourceProviders = filterSubClasses( ResourceProvider.class, classes); @@ -320,9 +346,7 @@ private Set> filterResourceProviders(Set> classes) { private Set> filterSubClasses(Class clazz, Set> classes) { return classes == null ? Collections.emptySet() - : classes.stream().filter(clazz::isAssignableFrom) - .filter(cls -> !cls.isInterface() && !cls.isSynthetic() - && !Modifier.isAbstract(cls.getModifiers())) + : classes.stream().filter(ReflectTools::isInstantiableService) .filter(cls -> !clazz.equals(cls)) .collect(Collectors.toSet()); } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 755ad95e44f..91080a204e6 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -7,15 +7,12 @@ import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; -import java.net.URLConnection; -import java.net.URLStreamHandler; import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; -import java.util.Hashtable; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -38,6 +35,7 @@ import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FallbackChunk.CssImportData; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; @@ -60,6 +58,10 @@ public class DeploymentConfigurationFactoryTest { private File tokenFile; private ServletContext contextMock; + private ApplicationConfiguration appConfiguration; + + private FallbackChunk fallbackChunk; + @Rule public ExpectedException exception = ExpectedException.none(); @@ -73,8 +75,15 @@ private static class ServletWithEnclosingUi extends VaadinServlet { } } - @VaadinServletConfiguration(productionMode = true, heartbeatInterval = 222) - private static class VaadinSettings extends VaadinServlet { + private static class TestDeploymentConfigurationFactory + extends DeploymentConfigurationFactory { + @Override + protected Properties createInitParameters( + Class systemPropertyBaseClass, VaadinConfig vaadinConfig) + throws VaadinConfigurationException { + return super.createInitParameters(systemPropertyBaseClass, + vaadinConfig); + } } @Before @@ -84,6 +93,7 @@ public void setup() throws IOException { tokenFile = new File(temporaryFolder.getRoot(), VAADIN_SERVLET_RESOURCES + TOKEN_FILE); FileUtils.writeLines(tokenFile, Arrays.asList("{", "}")); + appConfiguration = mockApplicationConfiguration(); contextMock = mock(ServletContext.class); defaultServletParams.put(PARAM_TOKEN_FILE, tokenFile.getPath()); @@ -137,83 +147,6 @@ public void servletWithNoEnclosingUI_hasDefaultUiInConfig() servlet), UI.class.getName(), config.getUIClassName()); } - @Test - public void vaadinServletConfigurationRead() throws Exception { - Class servlet = VaadinSettings.class; - - Map servletConfigParams = new HashMap<>( - defaultServletParams); - - DeploymentConfiguration config = new DeploymentConfigurationFactory() - .createDeploymentConfiguration(servlet, createVaadinConfigMock( - servletConfigParams, emptyMap())); - - assertTrue(String.format( - "Unexpected value for production mode, check '%s' class annotation", - servlet), config.isProductionMode()); - assertEquals(String.format( - "Unexpected value for heartbeat interval, check '%s' class annotation", - servlet), 222, config.getHeartbeatInterval()); - } - - @Test - public void servletConfigParametersOverrideVaadinParameters() - throws Exception { - Class servlet = VaadinSettings.class; - - boolean overridingProductionModeValue = false; - int overridingHeartbeatIntervalValue = 444; - - Map servletConfigParams = new HashMap<>( - defaultServletParams); - servletConfigParams.put(SERVLET_PARAMETER_PRODUCTION_MODE, - Boolean.toString(overridingProductionModeValue)); - servletConfigParams.put( - InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, - Integer.toString(overridingHeartbeatIntervalValue)); - - DeploymentConfiguration config = new DeploymentConfigurationFactory() - .createDeploymentConfiguration(servlet, createVaadinConfigMock( - servletConfigParams, emptyMap())); - - assertEquals( - "Unexpected value for production mode, should be the same as in servlet config parameters", - overridingProductionModeValue, config.isProductionMode()); - assertEquals( - "Unexpected value for heartbeat interval, should be the same as in servlet config parameters", - overridingHeartbeatIntervalValue, - config.getHeartbeatInterval()); - } - - @Test - public void servletContextParametersOverrideVaadinParameters() - throws Exception { - Class servlet = VaadinSettings.class; - - boolean overridingProductionModeValue = false; - int overridingHeartbeatIntervalValue = 444; - - Map servletContextParams = new HashMap<>( - defaultServletParams); - servletContextParams.put(SERVLET_PARAMETER_PRODUCTION_MODE, - Boolean.toString(overridingProductionModeValue)); - servletContextParams.put( - InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, - Integer.toString(overridingHeartbeatIntervalValue)); - - DeploymentConfiguration config = new DeploymentConfigurationFactory() - .createDeploymentConfiguration(servlet, createVaadinConfigMock( - emptyMap(), servletContextParams)); - - assertEquals( - "Unexpected value for production mode, should be the same as in servlet context parameters", - overridingProductionModeValue, config.isProductionMode()); - assertEquals( - "Unexpected value for heartbeat interval, should be the same as in servlet context parameters", - overridingHeartbeatIntervalValue, - config.getHeartbeatInterval()); - } - @Test public void servletConfigParametersOverrideServletContextParameters() throws Exception { @@ -359,34 +292,35 @@ public void shouldNotThrow_tokenFileFoldersExist() throws Exception { } @Test - public void externalStatsFileTrue_predefinedContext() throws Exception { - FileUtils.writeLines(tokenFile, - Arrays.asList("{", "\"externalStatsFile\": true", "}")); + public void createInitParameters_valuesFromContextAreIgnored_valuesAreTakenFromservletConfig() + throws Exception { + TestDeploymentConfigurationFactory factory = new TestDeploymentConfigurationFactory(); - DeploymentConfiguration config = createConfig(Collections - .singletonMap(PARAM_TOKEN_FILE, tokenFile.getPath())); + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); - assertEquals(false, config.isProductionMode()); - assertEquals(false, config.enableDevServer()); - assertEquals(true, config.isStatsExternal()); - assertEquals(Constants.DEFAULT_EXTERNAL_STATS_URL, - config.getExternalStatsUrl()); - } + Mockito.when(config.getVaadinContext()).thenReturn(context); - @Test - public void externalStatsUrlGiven_predefinedContext() throws Exception { - FileUtils.writeLines(tokenFile, Arrays.asList("{", - "\"externalStatsUrl\": \"http://my.server/static/stats.json\"", - "}")); + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); - DeploymentConfiguration config = createConfig(Collections - .singletonMap(PARAM_TOKEN_FILE, tokenFile.getPath())); + Mockito.when(config.getConfigParameterNames()).thenReturn( + Collections.enumeration(Collections.singleton("foo"))); + Mockito.when(context.getContextParameterNames()).thenReturn( + Collections.enumeration(Collections.singleton("bar"))); - assertEquals(false, config.isProductionMode()); - assertEquals(false, config.enableDevServer()); - assertEquals(true, config.isStatsExternal()); - assertEquals("http://my.server/static/stats.json", - config.getExternalStatsUrl()); + Mockito.when(config.getConfigParameter("foo")).thenReturn("baz"); + Mockito.when(context.getContextParameter("bar")).thenReturn("foobar"); + + Mockito.when(context.getAttribute( + Mockito.eq(ApplicationConfiguration.class), Mockito.any())) + .thenReturn(appConfig); + + Properties parameters = factory.createInitParameters(Object.class, + config); + + Assert.assertEquals("baz", parameters.get("foo")); + Assert.assertFalse(parameters.contains("bar")); } @Test @@ -413,21 +347,47 @@ public void externalStatsFileTrue_predefinedValuesAreNotOverridden() } @Test - public void createInitParameters_fallbackChunkObjectIsInInitParams() + public void createInitParameters_fallbackChunkIsCreatedViaAppConfig_fallbackChunkObjectIsInInitParams() throws VaadinConfigurationException, IOException { ServletContext context = Mockito.mock(ServletContext.class); ServletConfig config = Mockito.mock(ServletConfig.class); + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); Mockito.when(config.getServletContext()).thenReturn(context); - Hashtable table = new Hashtable<>( - Collections.singletonMap(FrontendUtils.PARAM_TOKEN_FILE, "")); - Mockito.when(context.getInitParameterNames()).thenReturn(table.keys()); + Mockito.when(config.getInitParameterNames()) + .thenReturn(Collections.emptyEnumeration()); + + Mockito.when( + context.getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + Mockito.when(appConfig.getFallbackChunk()).thenReturn(fallbackChunk); + + Properties properties = new DeploymentConfigurationFactory() + .createInitParameters(Object.class, + new VaadinServletConfig(config)); + Object object = properties + .get(DeploymentConfigurationFactory.FALLBACK_CHUNK); + + Assert.assertSame(fallbackChunk, object); + } + + @Test + public void createInitParameters_servletConfigDefinesTokenFile_fallbackChunkObjectIsInInitParams() + throws IOException, VaadinConfigurationException { + ServletContext context = Mockito.mock(ServletContext.class); + ServletConfig config = Mockito.mock(ServletConfig.class); + Mockito.when(config.getServletContext()).thenReturn(context); Mockito.when(config.getInitParameterNames()) - .thenReturn(new Hashtable().keys()); + .thenReturn(Collections.enumeration( + Collections.singleton(FrontendUtils.PARAM_TOKEN_FILE))); File tokenFile = temporaryFolder.newFile(); + Mockito.when(config.getInitParameter(FrontendUtils.PARAM_TOKEN_FILE)) + .thenReturn(tokenFile.getPath()); + Files.write(tokenFile.toPath(), Collections.singletonList("{ 'chunks': { " + "'fallback': {" + " 'jsModules': ['foo', 'bar']," @@ -473,60 +433,6 @@ public void createInitParameters_readDevModeProperties() throws Exception { .getProperty(InitParameters.REQUIRE_HOME_NODE_EXECUTABLE)); } - @Test - public void createInitParameters_readTokenFileFromContext() - throws VaadinConfigurationException, IOException { - VaadinContext context = Mockito.mock(VaadinContext.class); - VaadinConfig config = Mockito.mock(VaadinConfig.class); - - ResourceProvider resourceProvider = mockResourceProvider(config, - context); - - new DeploymentConfigurationFactory().createInitParameters( - DeploymentConfigurationFactoryTest.class, config); - - Mockito.verify(resourceProvider) - .getApplicationResources(VAADIN_SERVLET_RESOURCES + TOKEN_FILE); - } - - @Test - public void createInitParameters_checkWebpackGeneratedFromContext() - throws VaadinConfigurationException, IOException { - VaadinContext context = Mockito.mock(VaadinContext.class); - VaadinConfig config = Mockito.mock(VaadinConfig.class); - - ResourceProvider resourceProvider = mockResourceProvider(config, - context); - - String path = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; - - File tmpFile = temporaryFolder.newFile(); - Files.write(tmpFile.toPath(), Collections.singletonList("{}")); - - URLStreamHandler handler = new URLStreamHandler() { - - @Override - protected URLConnection openConnection(URL u) throws IOException { - return tmpFile.toURI().toURL().openConnection(); - } - }; - URL url = new URL("file", "", -1, "foo.jar!/" + path, handler); - - Mockito.when(resourceProvider.getApplicationResources(path)) - .thenReturn(Collections.singletonList(url)); - - Mockito.when(resourceProvider - .getApplicationResource(FrontendUtils.WEBPACK_GENERATED)) - .thenReturn(tmpFile.toURI().toURL()); - - new DeploymentConfigurationFactory().createInitParameters( - DeploymentConfigurationFactoryTest.class, config); - - Mockito.verify(resourceProvider) - .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); - - } - @Test public void createInitParameters_initParamtersAreSet_tokenDevModePropertiesAreNotSet() throws Exception { @@ -569,23 +475,22 @@ private VaadinConfig createVaadinConfigMock( servletConfigParameters, servletContextParameters)); } - private ResourceProvider mockResourceProvider(VaadinConfig config, - VaadinContext context) throws VaadinConfigurationException { - Mockito.when(config.getVaadinContext()).thenReturn(context); + private ApplicationConfiguration mockApplicationConfiguration() { + ApplicationConfiguration configuration = mock( + ApplicationConfiguration.class); + expect(configuration.enableDevServer()).andReturn(true).anyTimes(); + expect(configuration.isProductionMode()).andReturn(true).anyTimes(); + expect(configuration.useV14Bootstrap()).andReturn(false).anyTimes(); + expect(configuration.getStringProperty(EasyMock.anyString(), + EasyMock.anyString())).andReturn(null).anyTimes(); - Mockito.when(context.getContextParameterNames()) - .thenReturn(Collections.emptyEnumeration()); - Mockito.when(config.getConfigParameterNames()) - .thenReturn(Collections.emptyEnumeration()); + fallbackChunk = mock(FallbackChunk.class); - Lookup lookup = Mockito.mock(Lookup.class); - ResourceProvider resourceProvider = Mockito - .mock(ResourceProvider.class); - Mockito.when(lookup.lookup(ResourceProvider.class)) - .thenReturn(resourceProvider); - Mockito.when(context.getAttribute(Lookup.class)).thenReturn(lookup); + expect(configuration.getFallbackChunk()).andReturn(fallbackChunk) + .anyTimes(); + replay(configuration); + return configuration; - return resourceProvider; } private ServletConfig createServletConfigMock( @@ -595,6 +500,10 @@ private ServletConfig createServletConfigMock( URLClassLoader classLoader = new URLClassLoader( new URL[] { temporaryFolder.getRoot().toURI().toURL() }); + expect(contextMock + .getAttribute(ApplicationConfiguration.class.getName())) + .andReturn(appConfiguration).anyTimes(); + expect(contextMock.getInitParameterNames()) .andAnswer(() -> Collections .enumeration(servletContextParameters.keySet())) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java new file mode 100644 index 00000000000..ac411ddf148 --- /dev/null +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server.startup; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.nio.file.Files; +import java.util.Collections; +import java.util.function.Function; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Mockito; + +import com.vaadin.flow.di.Lookup; +import com.vaadin.flow.di.ResourceProvider; +import com.vaadin.flow.server.VaadinConfig; +import com.vaadin.flow.server.VaadinConfigurationException; +import com.vaadin.flow.server.VaadinContext; +import com.vaadin.flow.server.frontend.FrontendUtils; + +import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; +import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; + +public class DefaultApplicationConfigurationFactoryTest { + + @Rule + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private static class TestDefaultApplicationConfigurationFactory + extends DefaultApplicationConfigurationFactory { + + @Override + protected String getTokenFileContent( + Function locationProvider) { + return super.getTokenFileContent(locationProvider); + } + } + + @Test + public void createInitParameters_checkWebpackGeneratedFromContext() + throws VaadinConfigurationException, IOException { + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); + + ResourceProvider resourceProvider = mockResourceProvider(config, + context); + + String path = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; + + File tmpFile = temporaryFolder.newFile(); + Files.write(tmpFile.toPath(), Collections.singletonList("{}")); + + URLStreamHandler handler = new URLStreamHandler() { + + @Override + protected URLConnection openConnection(URL u) throws IOException { + return tmpFile.toURI().toURL().openConnection(); + } + }; + URL url = new URL("file", "", -1, "foo.jar!/" + path, handler); + + Mockito.when(resourceProvider.getApplicationResources(path)) + .thenReturn(Collections.singletonList(url)); + + Mockito.when(resourceProvider + .getApplicationResource(FrontendUtils.WEBPACK_GENERATED)) + .thenReturn(tmpFile.toURI().toURL()); + + TestDefaultApplicationConfigurationFactory factory = new TestDefaultApplicationConfigurationFactory(); + + factory.getTokenFileFromClassloader(context); + + Mockito.verify(resourceProvider) + .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); + + } + + private ResourceProvider mockResourceProvider(VaadinConfig config, + VaadinContext context) throws VaadinConfigurationException { + Mockito.when(config.getVaadinContext()).thenReturn(context); + + Mockito.when(context.getContextParameterNames()) + .thenReturn(Collections.emptyEnumeration()); + Mockito.when(config.getConfigParameterNames()) + .thenReturn(Collections.emptyEnumeration()); + + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + + Mockito.when(context.getAttribute(ApplicationConfiguration.class)) + .thenReturn(appConfig); + Mockito.when(context.getAttribute( + Mockito.eq(ApplicationConfiguration.class), Mockito.any())) + .thenReturn(appConfig); + + Lookup lookup = Mockito.mock(Lookup.class); + ResourceProvider resourceProvider = Mockito + .mock(ResourceProvider.class); + Mockito.when(lookup.lookup(ResourceProvider.class)) + .thenReturn(resourceProvider); + Mockito.when(context.getAttribute(Lookup.class)).thenReturn(lookup); + + return resourceProvider; + } +} From 37d103032bdc7d420946752bf2cb6de3fe6336de Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 16 Dec 2020 09:44:06 +0300 Subject: [PATCH 07/32] fix: correct variable name --- .../startup/DefaultApplicationConfigurationFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java index f6d37e0836e..f6e721d66db 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -92,9 +92,9 @@ public FallbackChunk getFallbackChunk() { @Override public ApplicationConfiguration create(VaadinContext context) { Map props = new HashMap<>(); - for (final Enumeration e = context.getContextParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); + for (final Enumeration paramNames = context + .getContextParameterNames(); paramNames.hasMoreElements();) { + final String name = paramNames.nextElement(); props.put(name, context.getContextParameter(name)); } JsonObject buildInfo = null; From b42bd480a42dab77bf163806fbb8c5a9fd401667 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 16 Dec 2020 13:24:48 +0300 Subject: [PATCH 08/32] test: make unit tests for DefaultApplicationConfigurationFactory --- .../function/DeploymentConfiguration.java | 19 +-- .../startup/AbstractConfigurationFactory.java | 2 - .../flow/server/startup/ServletDeployer.java | 2 - .../PropertyDeploymentConfigurationTest.java | 20 +++ .../VaadinServletConfigurationTest.java | 131 ------------------ ...ltApplicationConfigurationFactoryTest.java | 104 ++++++++++---- 6 files changed, 103 insertions(+), 175 deletions(-) create mode 100644 flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java delete mode 100644 flow-server/src/test/java/com/vaadin/flow/server/VaadinServletConfigurationTest.java diff --git a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java index 22aacf3efdc..40b27eef535 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java @@ -277,22 +277,9 @@ default List getPolyfills() { } /** - * <<<<<<< Upstream, based on master ======= Get if the dev server should be - * enabled. True by default - * - * @return true if dev server should be used - */ - @Override - default boolean enableDevServer() { - return getBooleanProperty( - InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, true); - } - - /** - * >>>>>>> 01eb234 refactor: extract common config functionality and - * introduce add config Get if the dev server should be reused on each - * reload. True by default, set it to false in tests so as dev server is not - * kept as a daemon after the test. + * Get if the dev server should be reused on each reload. True by default, + * set it to false in tests so as dev server is not kept as a daemon after + * the test. * * @return true if dev server should be reused */ diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java index 9290490048c..7da7e285043 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -183,8 +183,6 @@ protected void setDevModePropertiesUsingTokenData( * @param locationProvider * the token file location provider * @return the token file location, may be {@code null} - * @throws IOException - * if an error occurs */ protected String getTokenFileContent( Function locationProvider) { diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java index a9bd8410996..93f1c7dc326 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java @@ -42,7 +42,6 @@ import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinServlet; import com.vaadin.flow.server.VaadinServletConfig; -import com.vaadin.flow.server.VaadinServletConfiguration; import com.vaadin.flow.server.VaadinServletContext; import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -71,7 +70,6 @@ * is set to {@code true}. * * @author Vaadin Ltd - * @see VaadinServletConfiguration#disableAutomaticServletRegistration() * @since 1.0 */ public class ServletDeployer implements ServletContextListener { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java new file mode 100644 index 00000000000..da04f3f5ea2 --- /dev/null +++ b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java @@ -0,0 +1,20 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow.server; + +public class PropertyDeploymentConfigurationTest { + +} diff --git a/flow-server/src/test/java/com/vaadin/flow/server/VaadinServletConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/VaadinServletConfigurationTest.java deleted file mode 100644 index ae8ae6e2216..00000000000 --- a/flow-server/src/test/java/com/vaadin/flow/server/VaadinServletConfigurationTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2000-2020 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.flow.server; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import java.util.Properties; - -import org.easymock.EasyMock; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import com.vaadin.flow.component.UI; -import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.di.ResourceProvider; -import com.vaadin.flow.function.DeploymentConfiguration; -import com.vaadin.flow.server.MockUIContainingServlet.ServletInUI; - -public class VaadinServletConfigurationTest { - - @Test - public void testEnclosingUIClass() throws Exception { - Properties servletInitParams = new Properties(); - ServletInUI servlet = new MockUIContainingServlet.ServletInUI(); - servlet.init(createServletConfig(servletInitParams)); - - Class uiClass = BootstrapHandler - .getUIClass(new VaadinServletRequest( - EasyMock.createMock(HttpServletRequest.class), - servlet.getService())); - Assert.assertEquals(MockUIContainingServlet.class, uiClass); - } - - @Test - public void testValuesFromAnnotation() throws ServletException { - Properties servletInitParams = new Properties(); - TestServlet servlet = new TestServlet(); - servlet.init(createServletConfig(servletInitParams)); - - DeploymentConfiguration configuration = servlet.getService() - .getDeploymentConfiguration(); - - Assert.assertEquals(true, configuration.isProductionMode()); - Assert.assertEquals(true, configuration.isCloseIdleSessions()); - Assert.assertEquals(1234, configuration.getHeartbeatInterval()); - - Class uiClass = BootstrapHandler - .getUIClass(new VaadinServletRequest( - EasyMock.createMock(HttpServletRequest.class), - servlet.getService())); - Assert.assertEquals(MockUIContainingServlet.class, uiClass); - } - - @Test - public void testValuesOverriddenForServlet() throws ServletException { - final boolean expectedBoolean = false; - final int expectedInt = 1111; - - Properties servletInitParams = new Properties(); - servletInitParams.setProperty( - InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS, - Boolean.toString(expectedBoolean)); - servletInitParams.setProperty( - InitParameters.SERVLET_PARAMETER_HEARTBEAT_INTERVAL, - Integer.toString(expectedInt)); - - TestServlet servlet = new TestServlet(); - servlet.init(createServletConfig(servletInitParams)); - - DeploymentConfiguration configuration = servlet.getService() - .getDeploymentConfiguration(); - - // Values from servlet init params take precedence - Assert.assertEquals(expectedBoolean, - configuration.isSendUrlsAsParameters()); - Assert.assertEquals(expectedInt, configuration.getHeartbeatInterval()); - - // Other params are as defined in the annotation - Assert.assertEquals(true, configuration.isCloseIdleSessions()); - - Class uiClass = BootstrapHandler - .getUIClass(new VaadinServletRequest( - EasyMock.createMock(HttpServletRequest.class), - servlet.getService())); - Assert.assertEquals(MockUIContainingServlet.class, uiClass); - } - - private MockServletConfig createServletConfig(Properties properties) { - MockServletConfig config = new MockServletConfig(properties); - ServletContext servletContext = config.getServletContext(); - Lookup lookup = Mockito.mock(Lookup.class); - servletContext.setAttribute(Lookup.class.getName(), lookup); - - ResourceProvider provider = Mockito.mock(ResourceProvider.class); - Mockito.when(lookup.lookup(ResourceProvider.class)) - .thenReturn(provider); - return config; - } - -} - -@VaadinServletConfiguration(productionMode = true, ui = MockUIContainingServlet.class, closeIdleSessions = true, heartbeatInterval = 1234) -class TestServlet extends VaadinServlet { - -} - -@VaadinServletConfiguration(productionMode = true, ui = MockUIContainingServlet.class) -class LegacyPropertyWarningTestServlet extends VaadinServlet { - -} - -@VaadinServletConfiguration(productionMode = true, ui = MockUIContainingServlet.class) -class LegacyPropertyEnabledTestServlet extends VaadinServlet { - -} diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java index ac411ddf148..abc462639fe 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java @@ -17,13 +17,15 @@ import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.nio.file.Files; import java.util.Collections; -import java.util.function.Function; +import java.util.List; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -37,6 +39,7 @@ import com.vaadin.flow.server.frontend.FrontendUtils; import static com.vaadin.flow.server.Constants.VAADIN_SERVLET_RESOURCES; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; import static com.vaadin.flow.server.frontend.FrontendUtils.TOKEN_FILE; public class DefaultApplicationConfigurationFactoryTest { @@ -44,29 +47,94 @@ public class DefaultApplicationConfigurationFactoryTest { @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - private static class TestDefaultApplicationConfigurationFactory - extends DefaultApplicationConfigurationFactory { + @Test + public void getTokenFileFromClassloader_tokenFileIsRead_checkWebpackGeneratedFromContext() + throws VaadinConfigurationException, IOException { + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); + + ResourceProvider resourceProvider = mockResourceProvider(config, + context); + + String path = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; + + String content = "{ 'foo':'bar' }"; + mockClassPathTokenFile(resourceProvider, content); - @Override - protected String getTokenFileContent( - Function locationProvider) { - return super.getTokenFileContent(locationProvider); - } + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + + String tokenFileContent = factory.getTokenFileFromClassloader(context); + + Mockito.verify(resourceProvider) + .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); + + Mockito.verify(resourceProvider).getApplicationResources(path); + + Assert.assertEquals(content, tokenFileContent.trim()); } @Test - public void createInitParameters_checkWebpackGeneratedFromContext() - throws VaadinConfigurationException, IOException { + public void create_tokenFileIsSetViaContext_tokenFileIsReadViaContextProperty_propertiesAreReadFromContext() + throws IOException { VaadinContext context = Mockito.mock(VaadinContext.class); - VaadinConfig config = Mockito.mock(VaadinConfig.class); + Mockito.when(context.getContextParameterNames()) + .thenReturn(Collections.enumeration( + Collections.singleton(FrontendUtils.PARAM_TOKEN_FILE))); + File tmpFile = temporaryFolder.newFile(); + String content = "{ '" + SERVLET_PARAMETER_USE_V14_BOOTSTRAP + + "':true }"; + Files.write(tmpFile.toPath(), Collections.singletonList(content)); + + Mockito.when( + context.getContextParameter(FrontendUtils.PARAM_TOKEN_FILE)) + .thenReturn(tmpFile.getPath()); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertEquals(2, propertyNames.size()); + Assert.assertEquals(FrontendUtils.PARAM_TOKEN_FILE, + propertyNames.get(0)); + Assert.assertEquals(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, + propertyNames.get(1)); + + Assert.assertTrue(configuration.useV14Bootstrap()); + } + + @Test + public void create_propertiesAreReadFromContext() + throws IOException, VaadinConfigurationException { + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); ResourceProvider resourceProvider = mockResourceProvider(config, context); + Mockito.when(context.getContextParameterNames()).thenReturn( + Collections.enumeration(Collections.singleton("foo"))); + Mockito.when(context.getContextParameter("foo")).thenReturn("bar"); + + mockClassPathTokenFile(resourceProvider, "{}"); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertEquals(1, propertyNames.size()); + Assert.assertEquals("foo", propertyNames.get(0)); + Assert.assertEquals("bar", + configuration.getStringProperty("foo", null)); + } + + private void mockClassPathTokenFile(ResourceProvider resourceProvider, + String content) throws IOException, MalformedURLException { String path = VAADIN_SERVLET_RESOURCES + TOKEN_FILE; File tmpFile = temporaryFolder.newFile(); - Files.write(tmpFile.toPath(), Collections.singletonList("{}")); + Files.write(tmpFile.toPath(), Collections.singletonList(content)); URLStreamHandler handler = new URLStreamHandler() { @@ -79,18 +147,6 @@ protected URLConnection openConnection(URL u) throws IOException { Mockito.when(resourceProvider.getApplicationResources(path)) .thenReturn(Collections.singletonList(url)); - - Mockito.when(resourceProvider - .getApplicationResource(FrontendUtils.WEBPACK_GENERATED)) - .thenReturn(tmpFile.toURI().toURL()); - - TestDefaultApplicationConfigurationFactory factory = new TestDefaultApplicationConfigurationFactory(); - - factory.getTokenFileFromClassloader(context); - - Mockito.verify(resourceProvider) - .getApplicationResource(FrontendUtils.WEBPACK_GENERATED); - } private ResourceProvider mockResourceProvider(VaadinConfig config, From 85ce4fde0cc05ae3ffe149206337c738cb822adc Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 16 Dec 2020 13:38:30 +0300 Subject: [PATCH 09/32] test: add unit tests for properties in DefaultDeploymentConfiguration --- .../DefaultDeploymentConfigurationTest.java | 91 +++++++++++++++++-- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java index 989ce1044ac..71070e0a787 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java @@ -17,6 +17,7 @@ import java.util.Properties; +import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; @@ -120,14 +121,6 @@ public void booleanValueRead_exceptionOnNonBooleanValue() { createDeploymentConfig(initParameters); } - private DefaultDeploymentConfiguration createDeploymentConfig( - Properties initParameters) { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); - return new DefaultDeploymentConfiguration(appConfig, - DefaultDeploymentConfigurationTest.class, initParameters); - } - @Test public void defaultPushUrl() { Properties initParameters = new Properties(); @@ -168,4 +161,86 @@ public void maxMessageSuspendTimeout_invalidValue_defaultValue() { initParameters); assertEquals(5000, config.getMaxMessageSuspendTimeout()); } + + @Test + public void isProductionMode_productionModeIsSetViaParentOnly_productionModeIsTakenFromParent() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isProductionMode()).thenReturn(true); + + // Note: application configuration doesn't contain production mode + // parameter ! + Assert.assertNull(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, null)); + + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, new Properties()); + Assert.assertTrue(config.isProductionMode()); + Assert.assertTrue(config.getProperties().isEmpty()); + } + + @Test + public void isProductionMode_productionModeIsSetViaPropertiesAndViaParent_productionModeIsTakenFromProperties() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isProductionMode()).thenReturn(false); + + Properties initParameters = new Properties(); + initParameters.setProperty( + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, + Boolean.TRUE.toString()); + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, initParameters); + // the deployment configuration parameter takes precedence over parent + // config + Assert.assertTrue(config.isProductionMode()); + } + + @Test + public void useV14Bootstrap_v14ModeIsSetViaParentOnly_v14ModeIsTakenFromParent() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.useV14Bootstrap()).thenReturn(true); + + // Note: application configuration doesn't contain production mode + // parameter ! + Assert.assertNull(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, null)); + + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, new Properties()); + Assert.assertTrue(config.useV14Bootstrap()); + Assert.assertTrue(config.getProperties().isEmpty()); + } + + @Test + public void useV14Bootstrap_v14ModeIsSetViaParentOnlyAndViaParent_v14ModeIsTakenFromParent() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.useV14Bootstrap()).thenReturn(true); + + Properties initParameters = new Properties(); + initParameters.setProperty( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, + Boolean.TRUE.toString()); + + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, initParameters); + // the deployment configuration parameter takes precedence over parent + // config + Assert.assertTrue(config.useV14Bootstrap()); + } + + private DefaultDeploymentConfiguration createDeploymentConfig( + Properties initParameters) { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + return createDeploymentConfig(appConfig, initParameters); + } + + private DefaultDeploymentConfiguration createDeploymentConfig( + ApplicationConfiguration appConfig, Properties initParameters) { + return new DefaultDeploymentConfiguration(appConfig, + DefaultDeploymentConfigurationTest.class, initParameters); + } } From 282fc3c0626668e5c88c9d4e4b11b2fbb671d73a Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 16 Dec 2020 14:02:10 +0300 Subject: [PATCH 10/32] test: add precedence tests for PropertyDeploymentConfiguration --- .../PropertyDeploymentConfigurationTest.java | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java index da04f3f5ea2..96eb2deb9f3 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java @@ -15,6 +15,161 @@ */ package com.vaadin.flow.server; +import java.util.Properties; + +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import com.vaadin.flow.server.startup.ApplicationConfiguration; + public class PropertyDeploymentConfigurationTest { + @Test + public void isProductionMode_modeIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isProductionMode()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.isProductionMode()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + + @Test + public void isProductionMode_modeIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isProductionMode()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, + Boolean.TRUE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.isProductionMode()); + Assert.assertEquals(properties, config.getInitParameters()); + } + + @Test + public void enableDevServer_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.enableDevServer()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + + @Test + public void enableDevServer_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.enableDevServer()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, + Boolean.TRUE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.enableDevServer()); + Assert.assertEquals(properties, config.getInitParameters()); + } + + @Test + public void useV14Bootstrap_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.useV14Bootstrap()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.useV14Bootstrap()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + + @Test + public void useV14Bootstrap_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.useV14Bootstrap()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, + Boolean.TRUE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.useV14Bootstrap()); + Assert.assertEquals(properties, config.getInitParameters()); + } + + @Test + public void isPnpmEnabled_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isPnpmEnabled()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.isPnpmEnabled()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + + @Test + public void isPnpmEnabled_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isPnpmEnabled()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, + Boolean.TRUE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.isPnpmEnabled()); + Assert.assertEquals(properties, config.getInitParameters()); + } + + @Test + public void getApplicationProperty_propertyIsDefinedInParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + + Mockito.when(appConfig.getStringProperty("foo", null)) + .thenReturn("bar"); + + PropertyDeploymentConfiguration configuration = createConfiguration( + appConfig, new Properties()); + + Assert.assertEquals("bar", configuration.getApplicationProperty("foo")); + // there is no any property + Assert.assertTrue(configuration.getInitParameters().isEmpty()); + } + + @Test + public void getApplicationProperty_propertyIsDefinedInPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + + Mockito.when(appConfig.getStringProperty("foo", null)) + .thenReturn("bar"); + + Properties properties = new Properties(); + properties.put("foo", "baz"); + + PropertyDeploymentConfiguration configuration = createConfiguration( + appConfig, properties); + + Assert.assertEquals("baz", configuration.getApplicationProperty("foo")); + Assert.assertEquals(properties, configuration.getInitParameters()); + } + + private PropertyDeploymentConfiguration createConfiguration( + ApplicationConfiguration appConfig, Properties properties) { + return new PropertyDeploymentConfiguration(appConfig, Object.class, + properties); + } } From e119e096d89ee87ba05ca44e5796f3acbadf059c Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Wed, 16 Dec 2020 14:47:03 +0300 Subject: [PATCH 11/32] test: add unit test for app config factory in lookup --- .../server/startup/LookupInitializer.java | 12 ++--- .../server/startup/LookupInitializerTest.java | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java index 2d3703c60dc..25a521f371d 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/LookupInitializer.java @@ -277,8 +277,8 @@ private void initStandardLookup(Set> classSet, for (Class serviceType : getServiceTypes()) { if (ResourceProvider.class.equals(serviceType)) { collectResourceProviders(classSet, services); - } - if (ApplicationConfigurationFactory.class.equals(serviceType)) { + } else if (ApplicationConfigurationFactory.class + .equals(serviceType)) { collectApplicationConfigurationFactories(classSet, services); } else { collectSubclasses(serviceType, classSet, services); @@ -330,9 +330,8 @@ private void collectApplicationConfigurationFactories( + SPI + classSet + ONE_IMPL_REQUIRED); } else { Class clazz = factories.iterator().next(); - services.put(DefaultApplicationConfigurationFactory.class, - Collections - .singletonList(ReflectTools.createInstance(clazz))); + services.put(ApplicationConfigurationFactory.class, Collections + .singletonList(ReflectTools.createInstance(clazz))); } } @@ -346,7 +345,8 @@ private Set> filterResourceProviders(Set> classes) { private Set> filterSubClasses(Class clazz, Set> classes) { return classes == null ? Collections.emptySet() - : classes.stream().filter(ReflectTools::isInstantiableService) + : classes.stream().filter(clazz::isAssignableFrom) + .filter(ReflectTools::isInstantiableService) .filter(cls -> !clazz.equals(cls)) .collect(Collectors.toSet()); } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/LookupInitializerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/LookupInitializerTest.java index 7007a8039ca..bc4e42e2306 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/LookupInitializerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/LookupInitializerTest.java @@ -45,6 +45,7 @@ import com.vaadin.flow.di.InstantiatorFactory; import com.vaadin.flow.di.Lookup; import com.vaadin.flow.di.ResourceProvider; +import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.startup.testdata.AnotherTestInstantiatorFactory; import com.vaadin.flow.server.startup.testdata.OneMoreTestInstantiatorFactory; import com.vaadin.flow.server.startup.testdata.TestInstantiatorFactory; @@ -75,6 +76,14 @@ public Object getTemplateItem(Component template, JsonObject argValue, } + public static class TestApplicationConfigurationFactory + implements ApplicationConfigurationFactory { + @Override + public ApplicationConfiguration create(VaadinContext context) { + return null; + } + } + @Test public void processLookupInitializer_resourceProviderIsProvidedAsScannedClass_lookupReturnsTheProviderInstance() throws ServletException { @@ -276,6 +285,43 @@ protected Collection> getServiceTypes() { Assert.assertTrue(list instanceof ArrayList); } + @Test + public void processApplicationConfigurationFactory_noAvailableFactory_defaultFactoryIsReturned() + throws ServletException { + assertProcessApplicationConfigurationFactory(); + } + + @Test + public void processApplicationConfigurationFactory_defaultFactoryOnly_defaultFactoryIsReturned() + throws ServletException { + assertProcessApplicationConfigurationFactory( + DefaultApplicationConfigurationFactory.class); + } + + @Test + public void processApplicationConfigurationFactory_factoryIsProvided_providedFactoryIsCreated() + throws ServletException { + Lookup lookup = mockLookup(DefaultApplicationConfigurationFactory.class, + TestApplicationConfigurationFactory.class); + + ApplicationConfigurationFactory config = lookup + .lookup(ApplicationConfigurationFactory.class); + Assert.assertNotNull(config); + Assert.assertTrue( + config instanceof TestApplicationConfigurationFactory); + } + + private void assertProcessApplicationConfigurationFactory( + Class... factoryTypes) throws ServletException { + Lookup lookup = mockLookup(factoryTypes); + + ApplicationConfigurationFactory config = lookup + .lookup(ApplicationConfigurationFactory.class); + Assert.assertNotNull(config); + Assert.assertTrue( + config instanceof DefaultApplicationConfigurationFactory); + } + private Lookup mockLookup(ServletContext context, Class... classes) throws ServletException { ArgumentCaptor lookupCapture = ArgumentCaptor From 352b98dea5483e57ff384ab73d7efb2ff71e340a Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 08:35:45 +0300 Subject: [PATCH 12/32] test: extend unit tests for PropertyDeploymentConfiguration --- .../function/DeploymentConfiguration.java | 12 - .../flow/server/AbstractConfiguration.java | 12 + .../vaadin/flow/server/DevModeHandler.java | 24 +- .../PropertyDeploymentConfiguration.java | 56 ++++- .../PropertyDeploymentConfigurationTest.java | 225 ++++++++++++++++-- 5 files changed, 273 insertions(+), 56 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java index 40b27eef535..7f8d4fc97b0 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java @@ -276,18 +276,6 @@ default List getPolyfills() { .collect(Collectors.toList()); } - /** - * Get if the dev server should be reused on each reload. True by default, - * set it to false in tests so as dev server is not kept as a daemon after - * the test. - * - * @return true if dev server should be reused - */ - default boolean reuseDevServer() { - return getBooleanProperty( - InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, true); - } - /** * Get if the stats.json file should be retrieved from an external service * or through the classpath. diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java index 1e18943f691..b72abcb421b 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java @@ -45,6 +45,18 @@ default boolean enableDevServer() { InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, true); } + /** + * Get if the dev server should be reused on each reload. True by default, + * set it to false in tests so as dev server is not kept as a daemon after + * the test. + * + * @return true if dev server should be reused + */ + default boolean reuseDevServer() { + return getBooleanProperty( + InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, true); + } + /** * Returns whether Vaadin is running in useDeprecatedV14Bootstrapping. * diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java index 28eba6c22ec..e0b96f2305c 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DevModeHandler.java @@ -18,6 +18,7 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -46,7 +47,6 @@ import org.slf4j.LoggerFactory; import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.internal.BrowserLiveReload; import com.vaadin.flow.internal.Pair; import com.vaadin.flow.server.communication.StreamRequestHandler; @@ -143,8 +143,8 @@ private DevModeHandler(Lookup lookup, int runningPort, File npmFolder, this.npmFolder = npmFolder; port = runningPort; - DeploymentConfiguration config = lookup - .lookup(DeploymentConfiguration.class); + ApplicationConfiguration config = lookup + .lookup(ApplicationConfiguration.class); reuseDevServer = config.reuseDevServer(); devServerPortFile = getDevServerPortFile(npmFolder); @@ -286,9 +286,11 @@ private static DevModeHandler createInstance(int runningPort, Lookup lookup, */ public boolean isDevModeRequest(HttpServletRequest request) { String pathInfo = request.getPathInfo(); - return pathInfo != null && (pathInfo.startsWith("/" + VAADIN_MAPPING) - || APP_THEME_PATTERN.matcher(pathInfo).find()) && !pathInfo - .startsWith("/" + StreamRequestHandler.DYN_RES_PREFIX); + return pathInfo != null + && (pathInfo.startsWith("/" + VAADIN_MAPPING) + || APP_THEME_PATTERN.matcher(pathInfo).find()) + && !pathInfo + .startsWith("/" + StreamRequestHandler.DYN_RES_PREFIX); } /** @@ -327,7 +329,7 @@ public boolean serveDevModeRequest(HttpServletRequest request, } // Redirect theme source request - if(APP_THEME_PATTERN.matcher(requestFilename).find()) { + if (APP_THEME_PATTERN.matcher(requestFilename).find()) { requestFilename = "/VAADIN/static" + requestFilename; } @@ -531,7 +533,7 @@ public void removeRunningDevServerPort() { FileUtils.deleteQuietly(devServerPortFile); } - private void runOnFutureComplete(DeploymentConfiguration config) { + private void runOnFutureComplete(ApplicationConfiguration config) { try { doStartDevModeServer(config); } catch (ExecutionFailedException exception) { @@ -565,7 +567,7 @@ private boolean checkPort() { } - private void doStartDevModeServer(DeploymentConfiguration config) + private void doStartDevModeServer(ApplicationConfiguration config) throws ExecutionFailedException { // If port is defined, means that webpack is already running if (port > 0) { @@ -612,7 +614,7 @@ private void doStartDevModeServer(DeploymentConfiguration config) } } - private boolean doStartWebpack(DeploymentConfiguration config, + private boolean doStartWebpack(ApplicationConfiguration config, Pair webPackFiles, long start) { ProcessBuilder processBuilder = new ProcessBuilder() .directory(npmFolder); @@ -701,7 +703,7 @@ private void reuseExistingPort(int port) { watchDog.set(null); } - private List makeCommands(DeploymentConfiguration config, + private List makeCommands(ApplicationConfiguration config, File webpack, File webpackConfig, String nodeExec) { List command = new ArrayList<>(); command.add(nodeExec); diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index 59ac3086784..df13cf99ed4 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.server; +import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -32,7 +33,6 @@ import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REQUEST_TIMING; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SEND_URLS_AS_PARAMETERS; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_SYNC_ID_CHECK; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; /** * The property handling implementation of {@link DeploymentConfiguration} based @@ -45,7 +45,10 @@ public class PropertyDeploymentConfiguration private final Class systemPropertyBaseClass; - private final Properties initialParameters; + /** + * Contains properties from both: parent config and provided properties. + */ + private final Properties allProperties; private final ApplicationConfiguration parentConfig; @@ -66,7 +69,7 @@ public PropertyDeploymentConfiguration( Class systemPropertyBaseClass, Properties initParameters) { super(filterStringProperties(initParameters)); this.parentConfig = parentConfig; - initialParameters = initParameters; + allProperties = mergeProperties(parentConfig, initParameters); this.systemPropertyBaseClass = systemPropertyBaseClass; } @@ -134,27 +137,42 @@ public String getApplicationProperty(String parameterName) { @Override public boolean isProductionMode() { - return getBooleanProperty(SERVLET_PARAMETER_PRODUCTION_MODE, - parentConfig.isProductionMode()); + if (isOwnProperty(SERVLET_PARAMETER_PRODUCTION_MODE)) { + return getBooleanProperty(SERVLET_PARAMETER_PRODUCTION_MODE, false); + } + return parentConfig.isProductionMode(); } @Override public boolean enableDevServer() { - return getBooleanProperty( - InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, - parentConfig.enableDevServer()); + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER)) { + return super.enableDevServer(); + } + return parentConfig.enableDevServer(); } @Override public boolean useV14Bootstrap() { - return getBooleanProperty(SERVLET_PARAMETER_USE_V14_BOOTSTRAP, - parentConfig.useV14Bootstrap()); + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP)) { + return super.useV14Bootstrap(); + } + return parentConfig.useV14Bootstrap(); } @Override public boolean isPnpmEnabled() { - return getBooleanProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, - parentConfig.isPnpmEnabled()); + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)) { + return super.isPnpmEnabled(); + } + return parentConfig.isPnpmEnabled(); + } + + @Override + public boolean reuseDevServer() { + if (isOwnProperty(InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER)) { + return super.reuseDevServer(); + } + return parentConfig.reuseDevServer(); } @Override @@ -212,7 +230,7 @@ public String getPushURL() { @Override public Properties getInitParameters() { - return initialParameters; + return allProperties; } /** @@ -258,6 +276,18 @@ protected ApplicationConfiguration getParentConfiguration() { return parentConfig; } + private Properties mergeProperties(ApplicationConfiguration config, + Properties properties) { + Properties result = new Properties(); + Enumeration propertyNames = config.getPropertyNames(); + while (propertyNames.hasMoreElements()) { + String property = propertyNames.nextElement(); + result.put(property, config.getStringProperty(property, null)); + } + result.putAll(properties); + return result; + } + private static Map filterStringProperties( Properties properties) { Map result = new HashMap<>(); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java index 96eb2deb9f3..6cc47cec5e9 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.server; +import java.util.Collections; import java.util.Properties; import org.junit.Assert; @@ -27,8 +28,7 @@ public class PropertyDeploymentConfigurationTest { @Test public void isProductionMode_modeIsProvidedViaParentOnly_valueFromParentIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.isProductionMode()).thenReturn(true); PropertyDeploymentConfiguration config = createConfiguration(appConfig, new Properties()); @@ -39,8 +39,7 @@ public void isProductionMode_modeIsProvidedViaParentOnly_valueFromParentIsReturn @Test public void isProductionMode_modeIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.isProductionMode()).thenReturn(false); Properties properties = new Properties(); @@ -54,8 +53,7 @@ public void isProductionMode_modeIsProvidedViaPropertiesAndParent_valueFromPrope @Test public void enableDevServer_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.enableDevServer()).thenReturn(true); PropertyDeploymentConfiguration config = createConfiguration(appConfig, new Properties()); @@ -64,10 +62,34 @@ public void enableDevServer_valueIsProvidedViaParentOnly_valueFromParentIsReturn Assert.assertTrue(config.getInitParameters().isEmpty()); } + @Test + public void reuseDevServer_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = mockAppConfig(); + Mockito.when(appConfig.reuseDevServer()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, + Boolean.TRUE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.reuseDevServer()); + Assert.assertEquals(properties, config.getInitParameters()); + } + + @Test + public void reuseDevServer_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = mockAppConfig(); + Mockito.when(appConfig.reuseDevServer()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.reuseDevServer()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + @Test public void enableDevServer_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.enableDevServer()).thenReturn(false); Properties properties = new Properties(); @@ -81,8 +103,7 @@ public void enableDevServer_valueIsProvidedViaPropertiesAndParent_valueFromPrope @Test public void useV14Bootstrap_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.useV14Bootstrap()).thenReturn(true); PropertyDeploymentConfiguration config = createConfiguration(appConfig, new Properties()); @@ -93,8 +114,7 @@ public void useV14Bootstrap_valueIsProvidedViaParentOnly_valueFromParentIsReturn @Test public void useV14Bootstrap_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.useV14Bootstrap()).thenReturn(false); Properties properties = new Properties(); @@ -108,8 +128,7 @@ public void useV14Bootstrap_valueIsProvidedViaPropertiesAndParent_valueFromPrope @Test public void isPnpmEnabled_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.isPnpmEnabled()).thenReturn(true); PropertyDeploymentConfiguration config = createConfiguration(appConfig, new Properties()); @@ -120,8 +139,7 @@ public void isPnpmEnabled_valueIsProvidedViaParentOnly_valueFromParentIsReturned @Test public void isPnpmEnabled_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.isPnpmEnabled()).thenReturn(false); Properties properties = new Properties(); @@ -135,8 +153,7 @@ public void isPnpmEnabled_valueIsProvidedViaPropertiesAndParent_valueFromPropert @Test public void getApplicationProperty_propertyIsDefinedInParentOnly_valueFromParentIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.getStringProperty("foo", null)) .thenReturn("bar"); @@ -151,8 +168,7 @@ public void getApplicationProperty_propertyIsDefinedInParentOnly_valueFromParent @Test public void getApplicationProperty_propertyIsDefinedInPropertiesAndParent_valueFromPropertiesIsReturned() { - ApplicationConfiguration appConfig = Mockito - .mock(ApplicationConfiguration.class); + ApplicationConfiguration appConfig = mockAppConfig(); Mockito.when(appConfig.getStringProperty("foo", null)) .thenReturn("bar"); @@ -167,6 +183,175 @@ public void getApplicationProperty_propertyIsDefinedInPropertiesAndParent_valueF Assert.assertEquals(properties, configuration.getInitParameters()); } + @Test + public void isProductionMode_modeIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.isProductionMode()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, null)) + .thenReturn(Boolean.FALSE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.isProductionMode()); + Assert.assertTrue(config.getInitParameters() + .containsKey(InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE)); + } + + @Test + public void enableDevServer_valueIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER, null)) + .thenReturn(Boolean.FALSE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.enableDevServer()); + Assert.assertTrue(config.getInitParameters().containsKey( + InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER)); + } + + @Test + public void useV14Bootstrap_valueIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.useV14Bootstrap()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP, null)) + .thenReturn(Boolean.FALSE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.useV14Bootstrap()); + Assert.assertTrue(config.getInitParameters().containsKey( + InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP)); + } + + @Test + public void isPnpmEnabled_valueIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.isPnpmEnabled()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_ENABLE_PNPM))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, null)) + .thenReturn(Boolean.FALSE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.isPnpmEnabled()); + Assert.assertTrue(config.getInitParameters() + .containsKey(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)); + } + + @Test + public void reuseDevServer_valueIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.reuseDevServer()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER, null)) + .thenReturn(Boolean.FALSE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.reuseDevServer()); + Assert.assertTrue(config.getInitParameters().containsKey( + InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER)); + } + + @Test + public void getInitParameters_prorprtiesAreMergedFromParentAndDeploymentConfig() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getPropertyNames()).thenReturn( + Collections.enumeration(Collections.singleton("foo"))); + + Mockito.when(appConfig.getStringProperty("foo", null)) + .thenReturn("foobar"); + + Properties properties = new Properties(); + properties.put("bar", "baz"); + PropertyDeploymentConfiguration configuration = createConfiguration( + appConfig, properties); + Properties initParameters = configuration.getInitParameters(); + + Assert.assertEquals("foobar", initParameters.get("foo")); + Assert.assertEquals("baz", initParameters.get("bar")); + } + + private ApplicationConfiguration mockAppConfig() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); + + return appConfig; + } + private PropertyDeploymentConfiguration createConfiguration( ApplicationConfiguration appConfig, Properties properties) { return new PropertyDeploymentConfiguration(appConfig, Object.class, From e91f0bef678d105c08ebf4f9a514c78e8a74a897 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 09:14:34 +0300 Subject: [PATCH 13/32] test: use App config in DevModeHandlerTest instead deployment config --- .../flow/server/DevModeHandlerTest.java | 55 ++++++++++++++----- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DevModeHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DevModeHandlerTest.java index 421b69342ee..5c4ebb8e991 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DevModeHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DevModeHandlerTest.java @@ -59,6 +59,7 @@ import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.server.communication.StreamRequestHandler; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.tests.util.MockDeploymentConfiguration; import static com.vaadin.flow.server.DevModeHandler.WEBPACK_SERVER; @@ -81,7 +82,7 @@ @SuppressWarnings("restriction") public class DevModeHandlerTest { - private MockDeploymentConfiguration configuration; + private ApplicationConfiguration configuration; private HttpServer httpServer; private int responseStatus; @@ -98,6 +99,11 @@ private static class CustomRuntimeException extends RuntimeException { } + public abstract static class TestAppConfig + implements ApplicationConfiguration { + + } + private String baseDir; @Before @@ -105,8 +111,8 @@ public void setup() throws Exception { baseDir = temporaryFolder.getRoot().getAbsolutePath(); npmFolder = temporaryFolder.getRoot(); - configuration = new MockDeploymentConfiguration(); - configuration.setProductionMode(false); + configuration = Mockito.mock(ApplicationConfiguration.class); + mockApplicationConfiguration(configuration); new File(baseDir, FrontendUtils.WEBPACK_CONFIG).createNewFile(); createStubWebpackServer("Compiled", 100, baseDir); @@ -216,8 +222,9 @@ public void should_Fail_When_WebpackPrematurelyExit() throws Exception { @Test public void should_CaptureWebpackOutput_When_Failed() throws Exception { - configuration.setApplicationOrSystemProperty( - SERVLET_PARAMETER_DEVMODE_WEBPACK_TIMEOUT, "100"); + Mockito.when(configuration.getStringProperty( + SERVLET_PARAMETER_DEVMODE_WEBPACK_TIMEOUT, null)) + .thenReturn("100"); createStubWebpackServer("Failed to compile", 300, baseDir); DevModeHandler handler = DevModeHandler.start(createDevModeLookup(), npmFolder, CompletableFuture.completedFuture(null)); @@ -236,7 +243,7 @@ public void should_CaptureWebpackOutput_When_Failed() throws Exception { @Test public void shouldNot_CreateInstance_When_ProductionMode() throws Exception { - configuration.setProductionMode(true); + Mockito.when(configuration.isProductionMode()).thenReturn(true); DevModeHandler handler = DevModeHandler.start(createDevModeLookup(), npmFolder, CompletableFuture.completedFuture(null)); assertNull(handler); @@ -245,7 +252,7 @@ public void shouldNot_CreateInstance_When_ProductionMode() @Test public void enableDevServerFalse_shouldNotCreateInstance() throws Exception { - configuration.setEnableDevServer(false); + Mockito.when(configuration.enableDevServer()).thenReturn(false); DevModeHandler handler = DevModeHandler.start(createDevModeLookup(), npmFolder, CompletableFuture.completedFuture(null)); assertNull(handler); @@ -397,9 +404,14 @@ public void vaadinServlet_forDifferentRequests_shouldHaveCorrectResponse() @Test public void should_GetStatsJson_From_Webpack() throws Exception { VaadinService vaadinService = mock(VaadinService.class); + DeploymentConfiguration configuration = Mockito + .mock(DeploymentConfiguration.class); Mockito.when(vaadinService.getDeploymentConfiguration()) .thenReturn(configuration); + Mockito.when(configuration.isProductionMode()).thenReturn(false); + Mockito.when(configuration.enableDevServer()).thenReturn(true); + String statsContent = "{}"; int port = prepareHttpServer(0, HTTP_OK, statsContent); DevModeHandler.start(port, createDevModeLookup(), npmFolder, @@ -441,9 +453,9 @@ public void startDevModeHandler_vaadinHomeNodeIsAFolder_throws() FrontendUtils.isWindows() ? "node/node.exe" : "node/node"); FileUtils.forceMkdir(node); - configuration.setApplicationOrSystemProperty( - InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, - Boolean.TRUE.toString()); + Mockito.when(configuration.getBooleanProperty( + InitParameters.REQUIRE_HOME_NODE_EXECUTABLE, false)) + .thenReturn(true); DevModeHandler.start(createDevModeLookup(), npmFolder, CompletableFuture.completedFuture(null)).join(); } finally { @@ -494,8 +506,8 @@ public void serveDevModeRequest_prepareTasksThrows_serveDevModeReturnsFalseAndDo @Test public void start_twoTimes_onlyOneHandlerInstanceIsCreated() { - MockDeploymentConfiguration configuration = Mockito - .spy(MockDeploymentConfiguration.class); + TestAppConfig conf = Mockito.spy(TestAppConfig.class); + mockApplicationConfiguration(conf); DevModeHandler handler = DevModeHandler.start(0, createDevModeLookup(configuration), npmFolder, CompletableFuture.completedFuture(null)); @@ -724,8 +736,23 @@ private Lookup createDevModeLookup() { return createDevModeLookup(configuration); } - private Lookup createDevModeLookup(DeploymentConfiguration config) { - return Lookup.of(config, DeploymentConfiguration.class); + private Lookup createDevModeLookup(ApplicationConfiguration config) { + return Lookup.of(config, ApplicationConfiguration.class); + } + + private void mockApplicationConfiguration( + ApplicationConfiguration appConfig) { + Mockito.when(appConfig.isProductionMode()).thenReturn(false); + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + + Mockito.when(appConfig.getStringProperty(Mockito.anyString(), + Mockito.anyString())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + String.class)); + Mockito.when(appConfig.getBooleanProperty(Mockito.anyString(), + Mockito.anyBoolean())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + Boolean.class)); } public static HttpServer createStubWebpackTcpListener(int port, int status, From 81ea8f38347134855209f77a40fc0864e25539ff Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 09:31:28 +0300 Subject: [PATCH 14/32] test: use app config instead of deployment config in unit tests --- .../IndexHtmlRequestHandlerTest.java | 27 +++++-- .../startup/DevModeInitializerTest.java | 70 ++++++++++--------- .../startup/DevModeInitializerTestBase.java | 31 +++++++- .../server/startup/ServletDeployerTest.java | 18 +++++ .../VaadinAppShellInitializerTest.java | 40 ++++++++--- 5 files changed, 135 insertions(+), 51 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandlerTest.java index f91f5810394..eddd3c51e92 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/IndexHtmlRequestHandlerTest.java @@ -44,7 +44,6 @@ import com.vaadin.flow.component.UI; import com.vaadin.flow.component.internal.JavaScriptBootstrapUI; import com.vaadin.flow.di.Lookup; -import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.internal.UsageStatistics; import com.vaadin.flow.server.AppShellRegistry; import com.vaadin.flow.server.DevModeHandler; @@ -55,6 +54,7 @@ import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.VaadinSession; import com.vaadin.flow.server.frontend.FrontendUtils; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.server.startup.VaadinAppShellInitializerTest.AppShellWithPWA; import com.vaadin.flow.server.startup.VaadinAppShellInitializerTest.MyAppShellWithConfigurator; import com.vaadin.tests.util.MockDeploymentConfiguration; @@ -448,10 +448,14 @@ public void should_attachWebpackErrors() throws Exception { // Create a DevModeHandler deploymentConfiguration.setEnableDevServer(true); deploymentConfiguration.setProductionMode(false); + + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + mockApplicationConfiguration(appConfig); + DevModeHandler handler = DevModeHandler.start(0, - Lookup.of(deploymentConfiguration, - DeploymentConfiguration.class), - npmFolder, CompletableFuture.completedFuture(null)); + Lookup.of(appConfig, ApplicationConfiguration.class), npmFolder, + CompletableFuture.completedFuture(null)); Method join = DevModeHandler.class.getDeclaredMethod("join"); join.setAccessible(true); join.invoke(handler); @@ -665,4 +669,19 @@ private HttpServletRequest createRequest(String pathInfo) { .getRequestURL(); return request; } + + private void mockApplicationConfiguration( + ApplicationConfiguration appConfig) { + Mockito.when(appConfig.isProductionMode()).thenReturn(false); + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + + Mockito.when(appConfig.getStringProperty(Mockito.anyString(), + Mockito.anyString())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + String.class)); + Mockito.when(appConfig.getBooleanProperty(Mockito.anyString(), + Mockito.anyBoolean())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + Boolean.class)); + } } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java index 8707635b5c9..3e315a8dc63 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java @@ -43,18 +43,17 @@ import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; -import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; import static com.vaadin.flow.server.Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT; +import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; import static com.vaadin.flow.server.Constants.RESOURCES_FRONTEND_DEFAULT; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_OPENAPI_JSON_FILE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.never;; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times;; @NotThreadSafe public class DevModeInitializerTest extends DevModeInitializerTestBase { @@ -235,8 +234,7 @@ public void should_Run_Updaters_when_NoWebpackFile() throws Exception { @Test public void should_Not_Run_Updaters_inProductionMode() throws Exception { - System.setProperty("vaadin." + SERVLET_PARAMETER_PRODUCTION_MODE, - "true"); + Mockito.when(appConfig.isProductionMode()).thenReturn(true); DevModeInitializer devModeInitializer = new DevModeInitializer(); devModeInitializer.onStartup(classes, servletContext); assertNull(DevModeHandler.getDevModeHandler()); @@ -267,8 +265,9 @@ public void listener_should_stopDevModeHandler_onDestroy() @Test public void shouldUseByteCodeScannerIfPropertySet() throws Exception { - initParams.put(InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, - "true"); + Mockito.when(appConfig.getBooleanProperty( + InitParameters.SERVLET_PARAMETER_DEVMODE_OPTIMIZE_BUNDLE, + false)).thenReturn(true); DevModeInitializer devModeInitializer = new DevModeInitializer(); final Set> classes = new HashSet<>(); classes.add(NotVisitedWithDeps.class); @@ -304,16 +303,16 @@ public void should_generateOpenApi_when_EndpointPresents() throws Exception { String originalJavaSourceFolder = null; File generatedOpenApiJson = Paths - .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); + .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + originalJavaSourceFolder = System + .getProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); // Configure a folder to check the endpoints, doesn't matter // which folder, since the actual task won't be run, just // to verify the mocked task is executed. System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, - javaSourceFolder.getRoot().getAbsolutePath()); + javaSourceFolder.getRoot().getAbsolutePath()); Assert.assertFalse(generatedOpenApiJson.exists()); DevModeInitializer devModeInitializer = new DevModeInitializer(); @@ -323,11 +322,11 @@ public void should_generateOpenApi_when_EndpointPresents() Mockito.verify(taskGenerateConnect, times(1)).execute(); } finally { if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); + System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, + originalJavaSourceFolder); } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + System.clearProperty( + "vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); } generatedOpenApiJson.delete(); } @@ -339,13 +338,13 @@ public void should_notGenerateOpenApi_when_EndpointIsNotUsed() throws Exception { String originalJavaSourceFolder = null; File generatedOpenApiJson = Paths - .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); + .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - Mockito.doReturn(null).when(lookup).lookup(EndpointGeneratorTaskFactory.class); + originalJavaSourceFolder = System + .getProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + System.clearProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + Mockito.doReturn(null).when(lookup) + .lookup(EndpointGeneratorTaskFactory.class); Assert.assertFalse(generatedOpenApiJson.exists()); devModeInitializer.onStartup(classes, servletContext); @@ -354,11 +353,11 @@ public void should_notGenerateOpenApi_when_EndpointIsNotUsed() Mockito.verify(taskGenerateConnect, never()).execute(); } finally { if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); + System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, + originalJavaSourceFolder); } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + System.clearProperty( + "vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); } generatedOpenApiJson.delete(); } @@ -368,14 +367,14 @@ public void should_notGenerateOpenApi_when_EndpointIsNotUsed() public void should_generateTs_files() throws Exception { String originalJavaSourceFolder = null; try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + originalJavaSourceFolder = System + .getProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); // Configure a folder to check the endpoints, doesn't matter // which folder, since the actual task won't be run, just // to verify the mocked task is executed. System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, - javaSourceFolder.getRoot().getAbsolutePath()); + javaSourceFolder.getRoot().getAbsolutePath()); DevModeInitializer devModeInitializer = new DevModeInitializer(); @@ -385,11 +384,11 @@ public void should_generateTs_files() throws Exception { Mockito.verify(taskGenerateConnect, times(1)).execute(); } finally { if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); + System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, + originalJavaSourceFolder); } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); + System.clearProperty( + "vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); } } } @@ -430,6 +429,10 @@ public void onStartup_devModeAlreadyStarted_shouldBeTrueWhenStarted() .thenAnswer(answer -> servletContextAttributes .get(answer.getArgumentAt(0, String.class))); + Mockito.when(servletContext + .getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + Lookup lookup = Mockito.mock(Lookup.class); ResourceProvider resourceProvider = Mockito .mock(ResourceProvider.class); @@ -589,4 +592,5 @@ private void loadingFsResources_allFilesExist(Collection urls, assertTrue("Resource doesn't load from given path", locations.get(0).exists()); } + } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java index cb557cf3c5e..f393e46363c 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java @@ -48,7 +48,7 @@ import static com.vaadin.flow.server.frontend.NodeUpdateTestUtil.createStubNode; import static com.vaadin.flow.server.frontend.NodeUpdateTestUtil.createStubWebpackServer; import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.any; +import static org.mockito.Matchers.any; /** * Base class for DevModeInitializer tests. It is an independent class so as it @@ -71,6 +71,8 @@ public class DevModeInitializerTestBase { TaskGenerateConnect taskGenerateConnect; TaskGenerateOpenApi taskGenerateOpenApi; + ApplicationConfiguration appConfig; + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule @@ -89,6 +91,9 @@ public void setup() throws Exception { baseDir = temporaryFolder.getRoot().getPath(); Boolean enablePnpm = Boolean.TRUE; + appConfig = Mockito.mock(ApplicationConfiguration.class); + mockApplicationConfiguration(appConfig); + createStubNode(false, true, enablePnpm, baseDir); createStubWebpackServer("Compiled", 500, baseDir); @@ -96,10 +101,15 @@ public void setup() throws Exception { ServletRegistration vaadinServletRegistration = Mockito .mock(ServletRegistration.class); - lookup = Mockito.mock(Lookup.class);; + Mockito.when(servletContext + .getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + + lookup = Mockito.mock(Lookup.class); Mockito.when(servletContext.getAttribute(Lookup.class.getName())) .thenReturn(lookup); - endpointGeneratorTaskFactory = Mockito.mock(EndpointGeneratorTaskFactory.class); + endpointGeneratorTaskFactory = Mockito + .mock(EndpointGeneratorTaskFactory.class); taskGenerateConnect = Mockito.mock(TaskGenerateConnect.class); taskGenerateOpenApi = Mockito.mock(TaskGenerateOpenApi.class); Mockito.doReturn(endpointGeneratorTaskFactory).when(lookup) @@ -216,6 +226,21 @@ public void runDestroy() throws Exception { devModeInitializer.contextDestroyed(null); } + private void mockApplicationConfiguration( + ApplicationConfiguration appConfig) { + Mockito.when(appConfig.isProductionMode()).thenReturn(false); + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + + Mockito.when(appConfig.getStringProperty(Mockito.anyString(), + Mockito.anyString())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + String.class)); + Mockito.when(appConfig.getBooleanProperty(Mockito.anyString(), + Mockito.anyBoolean())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + Boolean.class)); + } + static List getClasspathURLs() { return Arrays.stream( System.getProperty("java.class.path").split(File.pathSeparator)) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/ServletDeployerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/ServletDeployerTest.java index bdd6aa64de0..89e721950ea 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/ServletDeployerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/ServletDeployerTest.java @@ -37,6 +37,7 @@ import com.vaadin.flow.router.RouteConfiguration; import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.VaadinServlet; +import com.vaadin.flow.server.frontend.FallbackChunk; import com.vaadin.flow.server.frontend.FrontendUtils; import com.vaadin.flow.server.webcomponent.WebComponentConfigurationRegistry; @@ -268,6 +269,23 @@ private ServletContextEvent getContextEvent(boolean addRoutes, replay(lookup); + ApplicationConfiguration appConfig = mock( + ApplicationConfiguration.class); + + expect(appConfig.getPropertyNames()) + .andReturn(Collections.emptyEnumeration()).anyTimes(); + expect(appConfig.getStringProperty(EasyMock.anyString(), + EasyMock.anyString())).andReturn(null).anyTimes(); + expect(appConfig.isProductionMode()).andReturn(false); + FallbackChunk chunk = mock(FallbackChunk.class); + expect(appConfig.getFallbackChunk()).andReturn(chunk).anyTimes(); + + replay(appConfig); + + expect(contextMock + .getAttribute(ApplicationConfiguration.class.getName())) + .andReturn(appConfig).anyTimes(); + expect(contextMock.getContextPath()).andReturn("").once(); expect(contextMock.getClassLoader()) .andReturn(this.getClass().getClassLoader()).anyTimes(); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/VaadinAppShellInitializerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/VaadinAppShellInitializerTest.java index 9b9f1b485e4..f1384077dc6 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/VaadinAppShellInitializerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/VaadinAppShellInitializerTest.java @@ -182,7 +182,6 @@ public static class AppShellWithPWA implements AppShellConfigurator { private ServletContext servletContext; private VaadinServletContext context; - private Map initParams; private Set> classes; private Document document; private Map attributeMap = new HashMap<>(); @@ -190,6 +189,7 @@ public static class AppShellWithPWA implements AppShellConfigurator { private MockServletServiceSessionSetup.TestVaadinServletService service; private PushConfiguration pushConfiguration; private Logger logger; + private ApplicationConfiguration appConfig; @Before public void setup() throws Exception { @@ -200,8 +200,11 @@ public void setup() throws Exception { servletContext = mocks.getServletContext(); + appConfig = mockApplicationConfiguration(); + attributeMap.put(Lookup.class.getName(), servletContext.getAttribute(Lookup.class.getName())); + attributeMap.put(ApplicationConfiguration.class.getName(), appConfig); service = mocks.getService(); Mockito.when(servletContext.getAttribute(Mockito.anyString())) @@ -216,9 +219,6 @@ public void setup() throws Exception { .mock(ServletRegistration.class); context = new VaadinServletContext(servletContext); - initParams = new HashMap<>(); - Mockito.when(registration.getInitParameters()).thenReturn(initParams); - classes = new HashSet<>(); Map registry = new HashMap<>(); @@ -380,7 +380,8 @@ public void should_throw_when_offendingClass() throws Exception { exception.expectMessage(containsString( "Found app shell configuration annotations in non")); exception.expectMessage(containsString( - "- @Meta, @Inline, @Viewport, @BodySize, @Push, @Theme" + " from")); + "- @Meta, @Inline, @Viewport, @BodySize, @Push, @Theme" + + " from")); classes.add(MyAppShellWithoutAnnotations.class); classes.add(OffendingClass.class); initializer.process(classes, servletContext); @@ -422,8 +423,8 @@ public void should_not_throw_when_classWithPageConfigurator() @Test public void should_not_throw_when_appShellAnnotationsAreAllowed_and_offendingClass() throws Exception { - initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, - Boolean.TRUE.toString()); + Mockito.when(appConfig.getBooleanProperty( + Constants.ALLOW_APPSHELL_ANNOTATIONS, false)).thenReturn(true); classes.add(OffendingClass.class); initializer.process(classes, servletContext); @@ -436,8 +437,8 @@ public void should_not_throw_when_appShellAnnotationsAreAllowed_and_offendingCla @Test public void should_link_to_PWA_article() throws Exception { - initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, - Boolean.TRUE.toString()); + Mockito.when(appConfig.getBooleanProperty( + Constants.ALLOW_APPSHELL_ANNOTATIONS, false)).thenReturn(true); ArgumentCaptor arg = ArgumentCaptor.forClass(String.class); classes.add(OffendingPwaClass.class); initializer.process(classes, servletContext); @@ -448,8 +449,8 @@ public void should_link_to_PWA_article() throws Exception { @Test public void should_not_link_to_PWA_article() throws Exception { - initParams.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, - Boolean.TRUE.toString()); + Mockito.when(appConfig.getBooleanProperty( + Constants.ALLOW_APPSHELL_ANNOTATIONS, false)).thenReturn(true); ArgumentCaptor arg = ArgumentCaptor.forClass(String.class); classes.add(OffendingNonPwaClass.class); initializer.process(classes, servletContext); @@ -491,4 +492,21 @@ private ConcurrentMap clearIlogger() throws Exception { map.clear(); return map; } + + private ApplicationConfiguration mockApplicationConfiguration() { + ApplicationConfiguration config = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(config.isProductionMode()).thenReturn(false); + Mockito.when(config.enableDevServer()).thenReturn(true); + + Mockito.when(config.getStringProperty(Mockito.anyString(), + Mockito.anyString())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + String.class)); + Mockito.when(config.getBooleanProperty(Mockito.anyString(), + Mockito.anyBoolean())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + Boolean.class)); + return config; + } } From 5e4a45d8479495100f02b1577cb0a16753745767 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 10:17:37 +0300 Subject: [PATCH 15/32] test: fixes unit tests after introducing merging properties --- .../flow/server/DefaultDeploymentConfigurationTest.java | 7 +++++++ .../server/communication/PushAtmosphereHandlerTest.java | 7 +++++-- .../flow/server/communication/UidlRequestHandlerTest.java | 7 +++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java index 71070e0a787..6e8d1512a62 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.server; +import java.util.Collections; import java.util.Properties; import org.junit.Assert; @@ -47,6 +48,8 @@ public void testGetSystemPropertyForDefaultPackage() Properties initParameters = new Properties(); ApplicationConfiguration appConfig = Mockito .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); DefaultDeploymentConfiguration config = new DefaultDeploymentConfiguration( appConfig, clazz, initParameters); assertEquals(value, config.getSystemProperty(prop)); @@ -63,6 +66,8 @@ public void testGetSystemProperty() throws ClassNotFoundException { Properties initParameters = new Properties(); ApplicationConfiguration appConfig = Mockito .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); DefaultDeploymentConfiguration config = new DefaultDeploymentConfiguration( appConfig, DefaultDeploymentConfigurationTest.class, initParameters); @@ -240,6 +245,8 @@ private DefaultDeploymentConfiguration createDeploymentConfig( private DefaultDeploymentConfiguration createDeploymentConfig( ApplicationConfiguration appConfig, Properties initParameters) { + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); return new DefaultDeploymentConfiguration(appConfig, DefaultDeploymentConfigurationTest.class, initParameters); } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java index ebc61ec692c..9cc2dae8fb8 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/PushAtmosphereHandlerTest.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.io.PrintWriter; +import java.util.Collections; import java.util.Properties; import org.atmosphere.cpr.AtmosphereRequest; @@ -54,10 +55,12 @@ public void setup() throws IOException { Mockito.when(resource.getRequest()).thenReturn(request); Mockito.when(resource.getResponse()).thenReturn(response); - ApplicationConfiguration congif = Mockito + ApplicationConfiguration config = Mockito .mock(ApplicationConfiguration.class); + Mockito.when(config.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); VaadinServletService service = new VaadinServletService(null, - new DefaultDeploymentConfiguration(congif, getClass(), + new DefaultDeploymentConfiguration(config, getClass(), new Properties())); PushHandler handler = new PushHandler(service); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java index 9e59cc3f654..15ddc12dc7c 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; +import java.util.Collections; import java.util.Properties; import org.junit.Assert; @@ -69,10 +70,12 @@ public void setup() throws IOException { @Test public void writeSessionExpired() throws Exception { - ApplicationConfiguration congif = Mockito + ApplicationConfiguration config = Mockito .mock(ApplicationConfiguration.class); + Mockito.when(config.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); VaadinService service = new VaadinServletService(null, - new DefaultDeploymentConfiguration(congif, getClass(), + new DefaultDeploymentConfiguration(config, getClass(), new Properties())); when(request.getService()).thenReturn(service); From 8cce983879f1991152a5091e54511a6918ef687c Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 11:31:11 +0300 Subject: [PATCH 16/32] test: fix DevModeInitializerClassLoaderTest --- .../server/DeploymentConfigurationFactoryTest.java | 3 +++ .../server/startup/DevModeInitializerTestBase.java | 14 ++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 91080a204e6..1a52b5ff9a1 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -484,6 +484,9 @@ private ApplicationConfiguration mockApplicationConfiguration() { expect(configuration.getStringProperty(EasyMock.anyString(), EasyMock.anyString())).andReturn(null).anyTimes(); + expect(configuration.getPropertyNames()) + .andReturn(Collections.emptyEnumeration()).anyTimes(); + fallbackChunk = mock(FallbackChunk.class); expect(configuration.getFallbackChunk()).andReturn(fallbackChunk) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java index f393e46363c..10513f2df65 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java @@ -28,7 +28,6 @@ import com.vaadin.flow.di.Lookup; import com.vaadin.flow.di.ResourceProvider; import com.vaadin.flow.server.DevModeHandler; -import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.VaadinServlet; import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -92,7 +91,7 @@ public void setup() throws Exception { Boolean enablePnpm = Boolean.TRUE; appConfig = Mockito.mock(ApplicationConfiguration.class); - mockApplicationConfiguration(appConfig); + mockApplicationConfiguration(appConfig, enablePnpm); createStubNode(false, true, enablePnpm, baseDir); createStubWebpackServer("Compiled", 500, baseDir); @@ -127,11 +126,6 @@ public void setup() throws Exception { Mockito.when(vaadinServletRegistration.getClassName()) .thenReturn(VaadinServletSubClass.class.getName()); - initParams = new HashMap<>(); - initParams.put(FrontendUtils.PROJECT_BASEDIR, baseDir); - initParams.put(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, - enablePnpm.toString()); - Mockito.when(vaadinServletRegistration.getInitParameters()) .thenReturn(initParams); @@ -227,9 +221,10 @@ public void runDestroy() throws Exception { } private void mockApplicationConfiguration( - ApplicationConfiguration appConfig) { + ApplicationConfiguration appConfig, boolean enablePnpm) { Mockito.when(appConfig.isProductionMode()).thenReturn(false); Mockito.when(appConfig.enableDevServer()).thenReturn(true); + Mockito.when(appConfig.isPnpmEnabled()).thenReturn(enablePnpm); Mockito.when(appConfig.getStringProperty(Mockito.anyString(), Mockito.anyString())) @@ -239,6 +234,9 @@ private void mockApplicationConfiguration( Mockito.anyBoolean())) .thenAnswer(invocation -> invocation.getArgumentAt(1, Boolean.class)); + + Mockito.when(appConfig.getStringProperty(FrontendUtils.PROJECT_BASEDIR, + null)).thenReturn(baseDir); } static List getClasspathURLs() { From 1b773f571118b3db98773573ebe3ffe98748eb01 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 11:44:41 +0300 Subject: [PATCH 17/32] fix: yet another fix of unit tests --- .../flow/server/CustomUIClassLoaderTest.java | 7 +++-- .../flow/server/frontend/TestUtils.java | 6 ++--- .../startup/DevModeInitializerTest.java | 26 +++++-------------- .../startup/DevModeInitializerTestBase.java | 4 --- 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java b/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java index a27e42d4969..5c594df9206 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/CustomUIClassLoaderTest.java @@ -1,6 +1,7 @@ package com.vaadin.flow.server; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Properties; @@ -61,9 +62,11 @@ public void testWithDefaultClassLoader() throws Exception { private static DeploymentConfiguration createConfigurationMock() { Properties properties = new Properties(); properties.put(InitParameters.UI_PARAMETER, MyUI.class.getName()); - ApplicationConfiguration congif = Mockito + ApplicationConfiguration config = Mockito .mock(ApplicationConfiguration.class); - return new DefaultDeploymentConfiguration(congif, + Mockito.when(config.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); + return new DefaultDeploymentConfiguration(config, CustomUIClassLoaderTest.class, properties); } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TestUtils.java b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TestUtils.java index 4b063696ed1..23b53fe00f3 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/frontend/TestUtils.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/frontend/TestUtils.java @@ -16,8 +16,6 @@ package com.vaadin.flow.server.frontend; -import static org.junit.Assert.assertNotNull; - import java.io.File; import java.io.IOException; import java.net.URL; @@ -26,6 +24,8 @@ import java.util.List; import java.util.stream.Collectors; +import static org.junit.Assert.assertNotNull; + /** * Shared code to use in the unit tests. * @@ -68,7 +68,7 @@ public static File getTestJar(String jarName) { */ public static File getTestFolder(String name) { File folder = new File(getTestResource(name).getFile()); - assert(folder.isDirectory()); + assert (folder.isDirectory()); return folder; } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java index 3e315a8dc63..836767e0cde 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTest.java @@ -13,7 +13,6 @@ import java.net.URLStreamHandler; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EventListener; @@ -46,7 +45,6 @@ import static com.vaadin.flow.server.Constants.COMPATIBILITY_RESOURCES_FRONTEND_DEFAULT; import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; import static com.vaadin.flow.server.Constants.RESOURCES_FRONTEND_DEFAULT; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_OPENAPI_JSON_FILE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -252,7 +250,7 @@ public void should_Not_AddContextListener() throws Exception { @Test public void listener_should_stopDevModeHandler_onDestroy() throws Exception { - initParams.put(SERVLET_PARAMETER_REUSE_DEV_SERVER, "false"); + Mockito.when(appConfig.reuseDevServer()).thenReturn(false); process(); @@ -397,19 +395,6 @@ public void should_generateTs_files() throws Exception { public void onStartup_emptyServletRegistrations_shouldCreateDevModeHandler() throws Exception { DevModeInitializer devModeInitializer = new DevModeInitializer(); - Mockito.when(servletContext.getServletRegistrations()) - .thenReturn(Collections.emptyMap()); - Mockito.when(servletContext.getInitParameterNames()) - .thenReturn(Collections.enumeration(new HashSet<>(Arrays.asList( - InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, - FrontendUtils.PROJECT_BASEDIR)))); - Mockito.when( - servletContext.getInitParameter(FrontendUtils.PROJECT_BASEDIR)) - .thenReturn(initParams.get(FrontendUtils.PROJECT_BASEDIR)); - Mockito.when(servletContext - .getInitParameter(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)) - .thenReturn(initParams - .get(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM)); devModeInitializer.onStartup(classes, servletContext); assertNotNull(DevModeHandler.getDevModeHandler()); } @@ -447,7 +432,8 @@ public void onStartup_devModeAlreadyStarted_shouldBeTrueWhenStarted() @Test(expected = IllegalStateException.class) public void onStartup_fallbackBaseDirIsNotProjectDirectory_throws() throws Exception { - initParams.remove(FrontendUtils.PROJECT_BASEDIR); + Mockito.when(appConfig.getStringProperty(FrontendUtils.PROJECT_BASEDIR, + null)).thenReturn(null); TemporaryFolder tmp = new TemporaryFolder(); tmp.create(); baseDir = tmp.getRoot().getPath(); @@ -467,7 +453,8 @@ public void onStartup_fallbackBaseDirIsNotProjectDirectory_throws() @Test public void onStartup_fallbackBaseDirIsMavenProjectDirectory_isAccepted() throws Exception { - initParams.remove(FrontendUtils.PROJECT_BASEDIR); + Mockito.when(appConfig.getStringProperty(FrontendUtils.PROJECT_BASEDIR, + null)).thenReturn(null); TemporaryFolder tmp = new TemporaryFolder(); tmp.create(); tmp.newFile("pom.xml"); @@ -488,7 +475,8 @@ public void onStartup_fallbackBaseDirIsMavenProjectDirectory_isAccepted() @Test public void onStartup_fallbackBaseDirIsGradleProjectDirectory_isAccepted() throws Exception { - initParams.remove(FrontendUtils.PROJECT_BASEDIR); + Mockito.when(appConfig.getStringProperty(FrontendUtils.PROJECT_BASEDIR, + null)).thenReturn(null); TemporaryFolder tmp = new TemporaryFolder(); tmp.create(); tmp.newFile("build.gradle"); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java index 10513f2df65..1ceeb799118 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DevModeInitializerTestBase.java @@ -60,7 +60,6 @@ public class DevModeInitializerTestBase { // These fields are intentionally scoped default so // as they can be used in package tests ServletContext servletContext; - Map initParams; Set> classes; File mainPackageFile; File webpackFile; @@ -126,9 +125,6 @@ public void setup() throws Exception { Mockito.when(vaadinServletRegistration.getClassName()) .thenReturn(VaadinServletSubClass.class.getName()); - Mockito.when(vaadinServletRegistration.getInitParameters()) - .thenReturn(initParams); - classes = new HashSet<>(); classes.add(this.getClass()); From 92f993d8ae1639a716276da329e147f0fedc5314 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 12:37:56 +0300 Subject: [PATCH 18/32] test: run ITs without app shell validation check --- ...efaultApplicationConfigurationFactory.java | 25 ++++++++++--- .../ItApplicationConfigurationFactory.java | 35 +++++++++++++++++++ .../java/com/vaadin/flow/osgi/Activator.java | 26 +++++++------- 3 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java index f6e721d66db..1cf13fa6f22 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -91,6 +91,7 @@ public FallbackChunk getFallbackChunk() { @Override public ApplicationConfiguration create(VaadinContext context) { + Objects.requireNonNull(context); Map props = new HashMap<>(); for (final Enumeration paramNames = context .getContextParameterNames(); paramNames.hasMoreElements();) { @@ -110,10 +111,26 @@ public ApplicationConfiguration create(VaadinContext context) { } catch (IOException exception) { throw new UncheckedIOException(exception); } - return new ApplicationConfigurationImpl(context, - buildInfo == null ? null - : FrontendUtils.readFallbackChunk(buildInfo), - props); + return doCreate(context, buildInfo == null ? null + : FrontendUtils.readFallbackChunk(buildInfo), props); + } + + /** + * Creates application configuration instance based on provided data. + * + * @param context + * the Vaadin context, not {@code null} + * @param chunk + * the fallback chunk, may be {@cod null} + * @param properties + * the context parameters, not {@code nulll} + * @return a new application configuration instance + */ + protected ApplicationConfigurationImpl doCreate(VaadinContext context, + FallbackChunk chunk, Map properties) { + Objects.requireNonNull(context); + Objects.requireNonNull(properties); + return new ApplicationConfigurationImpl(context, chunk, properties); } /** diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java new file mode 100644 index 00000000000..f2a5441c9e6 --- /dev/null +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2020 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.flow; + +import java.util.Map; + +import com.vaadin.flow.server.Constants; +import com.vaadin.flow.server.VaadinContext; +import com.vaadin.flow.server.frontend.FallbackChunk; +import com.vaadin.flow.server.startup.DefaultApplicationConfigurationFactory; + +public class ItApplicationConfigurationFactory + extends DefaultApplicationConfigurationFactory { + + @Override + protected ApplicationConfigurationImpl doCreate(VaadinContext context, + FallbackChunk chunk, Map properties) { + properties.put(Constants.ALLOW_APPSHELL_ANNOTATIONS, + Boolean.TRUE.toString()); + return super.doCreate(context, chunk, properties); + } +} diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/osgi/Activator.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/osgi/Activator.java index d0accef12b2..3d4657e7c4c 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/osgi/Activator.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/osgi/Activator.java @@ -33,7 +33,7 @@ import org.osgi.service.http.context.ServletContextHelper; import org.osgi.service.http.whiteboard.HttpWhiteboardConstants; -import com.vaadin.flow.server.VaadinServletConfiguration; +import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.uitest.servlet.ProductionModeTimingDataViewTestServlet; import com.vaadin.flow.uitest.servlet.ProductionModeViewTestServlet; import com.vaadin.flow.uitest.servlet.RouterTestServlet; @@ -72,7 +72,6 @@ public void ungetService(Bundle bundle, } - @VaadinServletConfiguration(productionMode = false) private static class FixedViewServlet extends ViewTestServlet { @Override public void init(ServletConfig servletConfig) throws ServletException { @@ -84,7 +83,6 @@ public void init(ServletConfig servletConfig) throws ServletException { } } - @VaadinServletConfiguration(productionMode = false) private static class FixedRouterServlet extends RouterTestServlet { @Override public void init(ServletConfig servletConfig) throws ServletException { @@ -96,7 +94,6 @@ public void init(ServletConfig servletConfig) throws ServletException { } } - @VaadinServletConfiguration(productionMode = true) private static class FixedProductionModeViewServlet extends ProductionModeViewTestServlet { @@ -110,7 +107,6 @@ public void init(ServletConfig servletConfig) throws ServletException { } } - @VaadinServletConfiguration(productionMode = true) private static class FixedProductionModeTimingDataViewServlet extends ProductionModeTimingDataViewTestServlet { @Override @@ -129,21 +125,21 @@ void activate() throws NamespaceException { .getBundleContext(); context.registerService(Servlet.class, new FixedViewServlet(), - createProperties("/view/*")); + createProperties("/view/*", false)); context.registerService(Servlet.class, new FixedViewServlet(), - createProperties("/context/*")); + createProperties("/context/*", false)); context.registerService(Servlet.class, new FixedRouterServlet(), - createProperties("/new-router-session/*")); + createProperties("/new-router-session/*", false)); context.registerService(Servlet.class, new FixedProductionModeViewServlet(), - createProperties("/view-production/*")); + createProperties("/view-production/*", true)); context.registerService(Servlet.class, new FixedProductionModeTimingDataViewServlet(), - createProperties("/view-production-timing/*")); + createProperties("/view-production-timing/*", true)); registerPlainJsResource(context); @@ -175,7 +171,8 @@ private String registerCustomContext(BundleContext context) { private void registerCustomContextServlet(BundleContext context, String contextName) { - Hashtable properties = createProperties("/view/*"); + Hashtable properties = createProperties("/view/*", + false); properties.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=" + contextName + ")"); @@ -183,8 +180,13 @@ private void registerCustomContextServlet(BundleContext context, properties); } - private Hashtable createProperties(String mapping) { + private Hashtable createProperties(String mapping, + Boolean isProductionMode) { Hashtable properties = new Hashtable<>(); + properties.put( + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX + + InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE, + isProductionMode.toString()); properties.put( HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, true); From dda1b6e952fb925ac0abf621f597ea5b269fd643 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 12:40:35 +0300 Subject: [PATCH 19/32] fix: yet another unit test fix --- .../flow/component/dnd/AbstractDnDUnitTest.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/flow-dnd/src/test/java/com/vaadin/flow/component/dnd/AbstractDnDUnitTest.java b/flow-dnd/src/test/java/com/vaadin/flow/component/dnd/AbstractDnDUnitTest.java index 96ecb2402da..3cfa76a152f 100644 --- a/flow-dnd/src/test/java/com/vaadin/flow/component/dnd/AbstractDnDUnitTest.java +++ b/flow-dnd/src/test/java/com/vaadin/flow/component/dnd/AbstractDnDUnitTest.java @@ -17,9 +17,15 @@ package com.vaadin.flow.component.dnd; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Properties; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + import com.vaadin.flow.component.Component; import com.vaadin.flow.component.dnd.internal.DnDUtilHelper; import com.vaadin.flow.component.internal.DependencyList; @@ -30,11 +36,8 @@ import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinServlet; import com.vaadin.flow.server.VaadinSession; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.shared.ui.Dependency; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; public abstract class AbstractDnDUnitTest { @@ -43,8 +46,12 @@ public abstract class AbstractDnDUnitTest { @Before public void setup() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.emptyEnumeration()); DefaultDeploymentConfiguration configuration = new DefaultDeploymentConfiguration( - VaadinServlet.class, new Properties()); + appConfig, VaadinServlet.class, new Properties()); VaadinService service = Mockito.mock(VaadinService.class); Mockito.when(service.resolveResource(Mockito.anyString())) From a1ef765199924c6db367fafd70234d8c3753ba72 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 12:47:12 +0300 Subject: [PATCH 20/32] fix: javadocs fix --- .../startup/DefaultApplicationConfigurationFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java index 1cf13fa6f22..a4ed85b7a52 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -121,9 +121,9 @@ public ApplicationConfiguration create(VaadinContext context) { * @param context * the Vaadin context, not {@code null} * @param chunk - * the fallback chunk, may be {@cod null} + * the fallback chunk, may be {@code null} * @param properties - * the context parameters, not {@code nulll} + * the context parameters, not {@code null} * @return a new application configuration instance */ protected ApplicationConfigurationImpl doCreate(VaadinContext context, From 865935a98cb39df885d88263d918852f3ee2de3e Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 13:08:10 +0300 Subject: [PATCH 21/32] fix: fix IT servets --- .../servlet/ProductionModeTimingDataViewTestServlet.java | 7 +++---- .../flow/uitest/servlet/ProductionModeViewTestServlet.java | 7 +++---- .../com/vaadin/flow/uitest/servlet/ViewTestServlet.java | 6 +++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeTimingDataViewTestServlet.java b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeTimingDataViewTestServlet.java index b6b8bc550ca..110e940c387 100644 --- a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeTimingDataViewTestServlet.java +++ b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeTimingDataViewTestServlet.java @@ -18,11 +18,10 @@ import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; -import com.vaadin.flow.server.VaadinServletConfiguration; - @WebServlet(asyncSupported = true, urlPatterns = { - "/view-production-timing/*" }, initParams = @WebInitParam(name = "requestTiming", value = "true")) -@VaadinServletConfiguration(productionMode = true) + "/view-production-timing/*" }, initParams = { + @WebInitParam(name = "requestTiming", value = "true"), + @WebInitParam(name = "productionMode", value = "true") }) public class ProductionModeTimingDataViewTestServlet extends ViewTestServlet { } diff --git a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeViewTestServlet.java b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeViewTestServlet.java index 79d701f1dba..2094a78c101 100644 --- a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeViewTestServlet.java +++ b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ProductionModeViewTestServlet.java @@ -15,12 +15,11 @@ */ package com.vaadin.flow.uitest.servlet; +import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; -import com.vaadin.flow.server.VaadinServletConfiguration; - -@WebServlet(asyncSupported = true, urlPatterns = { "/view-production/*" }) -@VaadinServletConfiguration(productionMode = true) +@WebServlet(asyncSupported = true, urlPatterns = { + "/view-production/*" }, initParams = @WebInitParam(name = "productionMode", value = "true")) public class ProductionModeViewTestServlet extends ViewTestServlet { } diff --git a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ViewTestServlet.java b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ViewTestServlet.java index 6bbcfbbe102..e575629a437 100644 --- a/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ViewTestServlet.java +++ b/flow-tests/test-common/src/main/java/com/vaadin/flow/uitest/servlet/ViewTestServlet.java @@ -17,13 +17,13 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletException; +import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import com.vaadin.flow.server.VaadinServlet; -import com.vaadin.flow.server.VaadinServletConfiguration; -@WebServlet(asyncSupported = true, urlPatterns = { "/view/*" }) -@VaadinServletConfiguration(productionMode = false) +@WebServlet(asyncSupported = true, urlPatterns = { + "/view/*" }, initParams = @WebInitParam(name = "productionMode", value = "false")) public class ViewTestServlet extends VaadinServlet { private static ViewClassLocator viewLocator; From 2044221dd41c3f1b793d8c5b24aac8f5933a0c61 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 13:39:22 +0300 Subject: [PATCH 22/32] fix: fix fusion code --- .../function/DeploymentConfiguration.java | 7 -- .../flow/server/AbstractConfiguration.java | 7 ++ .../DefaultDeploymentConfiguration.java | 12 ++- .../PropertyDeploymentConfiguration.java | 7 +- .../DefaultDeploymentConfigurationTest.java | 36 +++++++ .../PropertyDeploymentConfigurationTest.java | 53 +++++++++++ .../connect/VaadinConnectController.java | 95 ++++++++----------- 7 files changed, 152 insertions(+), 65 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java index 7f8d4fc97b0..2a6455ac7ff 100644 --- a/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/function/DeploymentConfiguration.java @@ -49,13 +49,6 @@ public interface DeploymentConfiguration */ boolean isRequestTiming(); - /** - * Returns whether cross-site request forgery protection is enabled. - * - * @return true if XSRF protection is enabled, false otherwise. - */ - boolean isXsrfProtectionEnabled(); - /** * Returns whether sync id checking is enabled. The sync id is used to * gracefully handle situations when the client sends a message to a diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java index b72abcb421b..ad63fb9d5dd 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java @@ -106,4 +106,11 @@ default boolean isPnpmEnabled() { Boolean.valueOf(Constants.ENABLE_PNPM_DEFAULT_STRING)); } + /** + * Returns whether cross-site request forgery protection is enabled. + * + * @return true if XSRF protection is enabled, false otherwise. + */ + boolean isXsrfProtectionEnabled(); + } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java index 5e646f18006..7bb225cf919 100755 --- a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java @@ -381,9 +381,15 @@ private void checkRequestTiming() { * Log a warning if cross-site request forgery protection is disabled. */ private void checkXsrfProtection(boolean loggWarning) { - xsrfProtectionEnabled = !getBooleanProperty( - InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, - false); + if (isOwnProperty( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)) { + xsrfProtectionEnabled = !getBooleanProperty( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + false); + } else { + xsrfProtectionEnabled = getParentConfiguration() + .isXsrfProtectionEnabled(); + } if (!xsrfProtectionEnabled && loggWarning) { warnings.add(WARNING_XSRF_PROTECTION_DISABLED); } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index df13cf99ed4..a8e4ea49da5 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -183,8 +183,11 @@ public boolean isRequestTiming() { @Override public boolean isXsrfProtectionEnabled() { - return !getBooleanProperty(SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, - false); + if (isOwnProperty(SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)) { + return !getBooleanProperty( + SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, false); + } + return parentConfig.isXsrfProtectionEnabled(); } @Override diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java index 6e8d1512a62..9fd98827710 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DefaultDeploymentConfigurationTest.java @@ -236,6 +236,42 @@ public void useV14Bootstrap_v14ModeIsSetViaParentOnlyAndViaParent_v14ModeIsTaken Assert.assertTrue(config.useV14Bootstrap()); } + @Test + public void isXsrfProtectionEnabled_valueIsSetViaParentOnly_valueIsTakenFromParent() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isXsrfProtectionEnabled()).thenReturn(true); + + // Note: application configuration doesn't contain production mode + // parameter ! + Assert.assertNull(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + null)); + + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, new Properties()); + Assert.assertTrue(config.isXsrfProtectionEnabled()); + Assert.assertTrue(config.getProperties().isEmpty()); + } + + @Test + public void isXsrfProtectionEnabled_valueIsSetViaParentOnlyAndViaParent_valueIsTakenFromParent() { + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + Mockito.when(appConfig.isXsrfProtectionEnabled()).thenReturn(false); + + Properties initParameters = new Properties(); + initParameters.setProperty( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + Boolean.FALSE.toString()); + + DefaultDeploymentConfiguration config = createDeploymentConfig( + appConfig, initParameters); + // the deployment configuration parameter takes precedence over parent + // config + Assert.assertTrue(config.isXsrfProtectionEnabled()); + } + private DefaultDeploymentConfiguration createDeploymentConfig( Properties initParameters) { ApplicationConfiguration appConfig = Mockito diff --git a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java index 6cc47cec5e9..64e33551579 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java @@ -151,6 +151,31 @@ public void isPnpmEnabled_valueIsProvidedViaPropertiesAndParent_valueFromPropert Assert.assertEquals(properties, config.getInitParameters()); } + @Test + public void isXsrfProtectionEnabled_valueIsProvidedViaParentOnly_valueFromParentIsReturned() { + ApplicationConfiguration appConfig = mockAppConfig(); + Mockito.when(appConfig.isXsrfProtectionEnabled()).thenReturn(true); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + Assert.assertTrue(config.isXsrfProtectionEnabled()); + // there is no any property + Assert.assertTrue(config.getInitParameters().isEmpty()); + } + + @Test + public void isXsrfProtectionEnabled_valueIsProvidedViaPropertiesAndParent_valueFromPropertiesIsReturned() { + ApplicationConfiguration appConfig = mockAppConfig(); + Mockito.when(appConfig.isXsrfProtectionEnabled()).thenReturn(false); + + Properties properties = new Properties(); + properties.put(InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + Boolean.FALSE.toString()); + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + properties); + Assert.assertTrue(config.isXsrfProtectionEnabled()); + Assert.assertEquals(properties, config.getInitParameters()); + } + @Test public void getApplicationProperty_propertyIsDefinedInParentOnly_valueFromParentIsReturned() { ApplicationConfiguration appConfig = mockAppConfig(); @@ -323,6 +348,34 @@ public void reuseDevServer_valueIsProvidedViaParentOnly_propertyIsSetToAnotherVa InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER)); } + @Test + public void isXsrfProtectionEnabled_valueIsProvidedViaParentOnly_propertyIsSetToAnotherValue_valueFromParentIsReturnedViaAPI() { + ApplicationConfiguration appConfig = mockAppConfig(); + + // The property value is provided via API + Mockito.when(appConfig.isXsrfProtectionEnabled()).thenReturn(true); + + // The property whose value is overridden above via API is different + Mockito.when(appConfig.getPropertyNames()) + .thenReturn(Collections.enumeration(Collections.singleton( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION))); + + Mockito.when(appConfig.getStringProperty( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, null)) + .thenReturn(Boolean.TRUE.toString()); + + PropertyDeploymentConfiguration config = createConfiguration(appConfig, + new Properties()); + // Several things are checked: the value from parent is used via API and + // deployment configuration doesn't read the property directly even + // though its "getInitParameters" method returns the property. Also + // "getApplicationProperty" method checks the parent properties which + // should not be taken into account here + Assert.assertTrue(config.isXsrfProtectionEnabled()); + Assert.assertTrue(config.getInitParameters().containsKey( + InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)); + } + @Test public void getInitParameters_prorprtiesAreMergedFromParentAndDeploymentConfig() { ApplicationConfiguration appConfig = Mockito diff --git a/fusion-endpoint/src/main/java/com/vaadin/flow/server/connect/VaadinConnectController.java b/fusion-endpoint/src/main/java/com/vaadin/flow/server/connect/VaadinConnectController.java index 8cf73b77731..7ef2eb37bd2 100644 --- a/fusion-endpoint/src/main/java/com/vaadin/flow/server/connect/VaadinConnectController.java +++ b/fusion-endpoint/src/main/java/com/vaadin/flow/server/connect/VaadinConnectController.java @@ -16,7 +16,6 @@ package com.vaadin.flow.server.connect; import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolation; import javax.validation.Validation; @@ -41,14 +40,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.googlecode.gentyref.GenericTypeReflector; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -67,17 +65,17 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.internal.CurrentInstance; import com.vaadin.flow.server.VaadinRequest; import com.vaadin.flow.server.VaadinService; +import com.vaadin.flow.server.VaadinServletContext; import com.vaadin.flow.server.VaadinServletRequest; import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.connect.auth.VaadinConnectAccessChecker; import com.vaadin.flow.server.connect.exception.EndpointException; import com.vaadin.flow.server.connect.exception.EndpointValidationException; import com.vaadin.flow.server.connect.exception.EndpointValidationException.ValidationErrorData; -import com.vaadin.flow.server.startup.ServletDeployer.StubServletConfig; +import com.vaadin.flow.server.startup.ApplicationConfiguration; /** * The controller that is responsible for processing Vaadin endpoint requests. @@ -107,8 +105,7 @@ public class VaadinConnectController { * EndpointNameChecker, ExplicitNullableTypeChecker, * ApplicationContext, ServletContext) */ - public static final String VAADIN_ENDPOINT_MAPPER_BEAN_QUALIFIER = - "vaadinEndpointMapper"; + public static final String VAADIN_ENDPOINT_MAPPER_BEAN_QUALIFIER = "vaadinEndpointMapper"; final Map vaadinEndpoints = new HashMap<>(); @@ -131,44 +128,44 @@ public class VaadinConnectController { * the ACL checker to verify the endpoint method access * permissions * @param endpointNameChecker - * the endpoint name checker to verify custom Vaadin - * endpoint names + * the endpoint name checker to verify custom Vaadin endpoint + * names * @param explicitNullableTypeChecker * the method parameter and return value type checker to verify * that null values are explicit * @param context - * Spring context to extract beans annotated with {@link Endpoint} - * from + * Spring context to extract beans annotated with + * {@link Endpoint} from * @param servletContext * The servlet context for the controller. */ public VaadinConnectController( - @Autowired(required = false) @Qualifier(VAADIN_ENDPOINT_MAPPER_BEAN_QUALIFIER) - ObjectMapper vaadinEndpointMapper, + @Autowired(required = false) @Qualifier(VAADIN_ENDPOINT_MAPPER_BEAN_QUALIFIER) ObjectMapper vaadinEndpointMapper, VaadinConnectAccessChecker accessChecker, EndpointNameChecker endpointNameChecker, ExplicitNullableTypeChecker explicitNullableTypeChecker, - ApplicationContext context, - ServletContext servletContext) { + ApplicationContext context, ServletContext servletContext) { this.vaadinEndpointMapper = vaadinEndpointMapper != null ? vaadinEndpointMapper : createVaadinConnectObjectMapper(context); this.accessChecker = accessChecker; this.explicitNullableTypeChecker = explicitNullableTypeChecker; - context.getBeansWithAnnotation(Endpoint.class).forEach( - (name, endpointBean) -> validateEndpointBean(endpointNameChecker, - name, endpointBean)); - + context.getBeansWithAnnotation(Endpoint.class) + .forEach((name, endpointBean) -> validateEndpointBean( + endpointNameChecker, name, endpointBean)); - DeploymentConfiguration cfg = createDeploymentConfiguration(servletContext); + ApplicationConfiguration cfg = ApplicationConfiguration + .get(new VaadinServletContext(servletContext)); if (cfg != null) { accessChecker.enableCsrf(cfg.isXsrfProtectionEnabled()); } } - private ObjectMapper createVaadinConnectObjectMapper(ApplicationContext context) { - Jackson2ObjectMapperBuilder builder = context.getBean(Jackson2ObjectMapperBuilder.class); + private ObjectMapper createVaadinConnectObjectMapper( + ApplicationContext context) { + Jackson2ObjectMapperBuilder builder = context + .getBean(Jackson2ObjectMapperBuilder.class); ObjectMapper objectMapper = builder.createXmlMapper(false).build(); JacksonProperties jacksonProperties = context .getBean(JacksonProperties.class); @@ -177,17 +174,6 @@ private ObjectMapper createVaadinConnectObjectMapper(ApplicationContext context) JsonAutoDetect.Visibility.ANY); } return objectMapper; - } - - private DeploymentConfiguration createDeploymentConfiguration( - ServletContext ctx) { - if (ctx.getServletRegistrations().isEmpty()) { - return null; - } - ServletRegistration reg = ctx.getServletRegistrations().entrySet() - .iterator().next().getValue(); - return StubServletConfig.createDeploymentConfiguration(ctx, reg, - VaadinConnectController.class); } private static Logger getLogger() { @@ -211,8 +197,8 @@ void validateEndpointBean(EndpointNameChecker endpointNameChecker, name, beanType, Endpoint.class) + String.format( "Either modify the bean declaration so that it is not an " - + "anonymous class or specify an endpoint " + - "name in the '%s' annotation", + + "anonymous class or specify an endpoint " + + "name in the '%s' annotation", Endpoint.class)); } String validationError = endpointNameChecker.check(endpointName); @@ -253,8 +239,7 @@ void validateEndpointBean(EndpointNameChecker endpointNameChecker, * the current request which triggers the endpoint call * @return execution result as a JSON string or an error message string */ - @PostMapping(path = "/{endpoint}/{method}", produces = - MediaType.APPLICATION_JSON_UTF8_VALUE) + @PostMapping(path = "/{endpoint}/{method}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public ResponseEntity serveEndpoint( @PathVariable("endpoint") String endpointName, @PathVariable("method") String methodName, @@ -282,8 +267,10 @@ public ResponseEntity serveEndpoint( // Put a VaadinRequest in the instances object so as the request is // available in the end-point method - VaadinServletService service = (VaadinServletService)VaadinService.getCurrent(); - CurrentInstance.set(VaadinRequest.class, new VaadinServletRequest(request, service)); + VaadinServletService service = (VaadinServletService) VaadinService + .getCurrent(); + CurrentInstance.set(VaadinRequest.class, + new VaadinServletRequest(request, service)); return invokeVaadinEndpointMethod(endpointName, methodName, methodToInvoke, body, vaadinEndpointData, request); @@ -304,14 +291,14 @@ public ResponseEntity serveEndpoint( errorMessage), unexpected); } } finally { - CurrentInstance.set(VaadinRequest.class, null); + CurrentInstance.set(VaadinRequest.class, null); } } - private ResponseEntity invokeVaadinEndpointMethod(String endpointName, - String methodName, Method methodToInvoke, ObjectNode body, - VaadinEndpointData vaadinEndpointData, HttpServletRequest request) - throws JsonProcessingException { + private ResponseEntity invokeVaadinEndpointMethod( + String endpointName, String methodName, Method methodToInvoke, + ObjectNode body, VaadinEndpointData vaadinEndpointData, + HttpServletRequest request) throws JsonProcessingException { String checkError = accessChecker.check(methodToInvoke, request); if (checkError != null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED) @@ -321,7 +308,8 @@ private ResponseEntity invokeVaadinEndpointMethod(String endpointName, } Map requestParameters = getRequestParameters(body); - Type[] javaParameters = getJavaParameters(methodToInvoke, ClassUtils.getUserClass(vaadinEndpointData.vaadinEndpointObject)); + Type[] javaParameters = getJavaParameters(methodToInvoke, ClassUtils + .getUserClass(vaadinEndpointData.vaadinEndpointObject)); if (javaParameters.length != requestParameters.size()) { return ResponseEntity.badRequest() .body(createResponseErrorObject(String.format( @@ -334,7 +322,8 @@ private ResponseEntity invokeVaadinEndpointMethod(String endpointName, Object[] vaadinEndpointParameters; try { vaadinEndpointParameters = getVaadinEndpointParameters( - requestParameters, javaParameters, methodName, endpointName); + requestParameters, javaParameters, methodName, + endpointName); } catch (EndpointValidationException e) { getLogger().debug( "Endpoint '{}' method '{}' received invalid response", @@ -411,14 +400,15 @@ private ResponseEntity invokeVaadinEndpointMethod(String endpointName, } private Type[] getJavaParameters(Method methodToInvoke, Type classType) { - return Stream.of(GenericTypeReflector.getExactParameterTypes(methodToInvoke, classType)).toArray(Type[]::new); + return Stream.of(GenericTypeReflector + .getExactParameterTypes(methodToInvoke, classType)) + .toArray(Type[]::new); } private ResponseEntity handleMethodExecutionError( String endpointName, String methodName, InvocationTargetException e) throws JsonProcessingException { - if (EndpointException.class - .isAssignableFrom(e.getCause().getClass())) { + if (EndpointException.class.isAssignableFrom(e.getCause().getClass())) { EndpointException endpointException = ((EndpointException) e .getCause()); getLogger().debug("Endpoint '{}' method '{}' aborted the execution", @@ -443,8 +433,8 @@ private String createResponseErrorObject(String errorMessage) } private String listMethodParameterTypes(Type[] javaParameters) { - return Stream.of(javaParameters) - .map(Type::getTypeName).collect(Collectors.joining(", ")); + return Stream.of(javaParameters).map(Type::getTypeName) + .collect(Collectors.joining(", ")); } private Object[] getVaadinEndpointParameters( @@ -509,8 +499,7 @@ private EndpointValidationException getInvalidEndpointParametersException( String message = String.format( "Validation error in endpoint '%s' method '%s'", endpointName, methodName); - return new EndpointValidationException(message, - validationErrorData); + return new EndpointValidationException(message, validationErrorData); } private List createBeanValidationErrors( From 497b282e9ec793402a5bb0398d79f3a87d98a71c Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Thu, 17 Dec 2020 13:49:12 +0300 Subject: [PATCH 23/32] it's never ending story --- .../java/com/vaadin/flow/server/AbstractConfiguration.java | 6 +++++- .../vaadin/flow/server/PropertyDeploymentConfiguration.java | 3 +-- .../flow/server/DeploymentConfigurationFactoryTest.java | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java index ad63fb9d5dd..3caa71d376f 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/AbstractConfiguration.java @@ -17,6 +17,7 @@ import java.io.Serializable; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION; import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_USE_V14_BOOTSTRAP; /** @@ -111,6 +112,9 @@ default boolean isPnpmEnabled() { * * @return true if XSRF protection is enabled, false otherwise. */ - boolean isXsrfProtectionEnabled(); + default boolean isXsrfProtectionEnabled() { + return !getBooleanProperty(SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, + false); + } } diff --git a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java index a8e4ea49da5..6df74f64a07 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/PropertyDeploymentConfiguration.java @@ -184,8 +184,7 @@ public boolean isRequestTiming() { @Override public boolean isXsrfProtectionEnabled() { if (isOwnProperty(SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)) { - return !getBooleanProperty( - SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, false); + return super.isXsrfProtectionEnabled(); } return parentConfig.isXsrfProtectionEnabled(); } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 1a52b5ff9a1..89854939775 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -483,6 +483,8 @@ private ApplicationConfiguration mockApplicationConfiguration() { expect(configuration.useV14Bootstrap()).andReturn(false).anyTimes(); expect(configuration.getStringProperty(EasyMock.anyString(), EasyMock.anyString())).andReturn(null).anyTimes(); + expect(configuration.isXsrfProtectionEnabled()).andReturn(false) + .anyTimes(); expect(configuration.getPropertyNames()) .andReturn(Collections.emptyEnumeration()).anyTimes(); From 777e9a80294e6ede8ced7f623471215892d70f4e Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 18 Dec 2020 09:38:13 +0300 Subject: [PATCH 24/32] chore: adapt fusion code to use app config and make factory OSGi capable --- flow-server/pom.xml | 9 + ...efaultApplicationConfigurationFactory.java | 4 + .../ItApplicationConfigurationFactory.java | 4 + .../connect/VaadinConnectControllerTest.java | 291 ++++++++++-------- .../rest/EndpointWithRestControllerTest.java | 72 +++-- .../BaseTypeConversionTest.java | 28 +- .../DevModeInitializerEndpointTest.java | 205 ++++++------ 7 files changed, 338 insertions(+), 275 deletions(-) diff --git a/flow-server/pom.xml b/flow-server/pom.xml index 1b2b7d73819..18465a06ba8 100644 --- a/flow-server/pom.xml +++ b/flow-server/pom.xml @@ -39,6 +39,15 @@ ${project.version} test + + + + + org.osgi + osgi.cmpn + ${osgi.compendium.version} + provided + diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java index a4ed85b7a52..d97b67b07a7 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactory.java @@ -25,6 +25,8 @@ import java.util.Map; import java.util.Objects; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.propertytypes.ServiceRanking; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,6 +51,8 @@ * @since * */ +@Component(service = ApplicationConfigurationFactory.class) +@ServiceRanking(Integer.MIN_VALUE) public class DefaultApplicationConfigurationFactory extends AbstractConfigurationFactory implements ApplicationConfigurationFactory { diff --git a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java index f2a5441c9e6..e80f627ab10 100644 --- a/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java +++ b/flow-tests/test-root-context/src/main/java/com/vaadin/flow/ItApplicationConfigurationFactory.java @@ -17,11 +17,15 @@ import java.util.Map; +import org.osgi.service.component.annotations.Component; + import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.frontend.FallbackChunk; +import com.vaadin.flow.server.startup.ApplicationConfigurationFactory; import com.vaadin.flow.server.startup.DefaultApplicationConfigurationFactory; +@Component(service = ApplicationConfigurationFactory.class) public class ItApplicationConfigurationFactory extends DefaultApplicationConfigurationFactory { diff --git a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/VaadinConnectControllerTest.java b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/VaadinConnectControllerTest.java index 402fe88c007..4648e47666a 100644 --- a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/VaadinConnectControllerTest.java +++ b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/VaadinConnectControllerTest.java @@ -28,7 +28,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.type.SimpleType; import com.fasterxml.jackson.databind.type.TypeFactory; - import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; @@ -51,8 +50,8 @@ import com.vaadin.flow.server.connect.exception.EndpointException; import com.vaadin.flow.server.connect.exception.EndpointValidationException; import com.vaadin.flow.server.connect.generator.endpoints.superclassmethods.PersonEndpoint; -import com.vaadin.flow.server.connect.generator.endpoints.superclassmethods.PersonEndpoint.Person; import com.vaadin.flow.server.connect.testendpoint.BridgeMethodTestEndpoint; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -60,12 +59,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.only; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -78,6 +76,7 @@ public class VaadinConnectControllerTest { private static final Method TEST_VALIDATION_METHOD; private HttpServletRequest requestMock; private Principal principal; + private ApplicationConfiguration appConfig; static { TEST_METHOD = Stream.of(TEST_ENDPOINT.getClass().getDeclaredMethods()) @@ -123,7 +122,7 @@ public String testAnonymousMethod() { } @PermitAll - @RolesAllowed({"FOO_ROLE", "BAR_ROLE"}) + @RolesAllowed({ "FOO_ROLE", "BAR_ROLE" }) public String testRoleAllowed() { return "Hello, user in role!"; } @@ -140,7 +139,8 @@ public String anonymousOverrides() { } public String getUserName() { - return VaadinService.getCurrentRequest().getUserPrincipal().getName(); + return VaadinService.getCurrentRequest().getUserPrincipal() + .getName(); } } @@ -179,12 +179,14 @@ public void setUp() { requestMock = mock(HttpServletRequest.class); principal = mock(Principal.class); + appConfig = Mockito.mock(ApplicationConfiguration.class); + when(requestMock.getUserPrincipal()).thenReturn(principal); when(requestMock.getHeader("X-CSRF-Token")).thenReturn("Vaadin CCDM"); HttpSession sessionMock = mock(HttpSession.class); - when(sessionMock.getAttribute(com.vaadin.flow.server.VaadinService.getCsrfTokenAttributeName())) - .thenReturn("Vaadin CCDM"); + when(sessionMock.getAttribute(com.vaadin.flow.server.VaadinService + .getCsrfTokenAttributeName())).thenReturn("Vaadin CCDM"); when(requestMock.getSession(false)).thenReturn(sessionMock); } @@ -203,8 +205,7 @@ public void should_ThrowException_When_NoEndpointNameCanBeReceived() { @Test public void should_ThrowException_When_IncorrectEndpointNameProvided() { - TestClassWithIllegalEndpointName endpointWithIllegalName = - new TestClassWithIllegalEndpointName(); + TestClassWithIllegalEndpointName endpointWithIllegalName = new TestClassWithIllegalEndpointName(); String incorrectName = endpointWithIllegalName.getClass() .getAnnotation(Endpoint.class).value(); EndpointNameChecker nameChecker = new EndpointNameChecker(); @@ -215,8 +216,8 @@ public void should_ThrowException_When_IncorrectEndpointNameProvided() { exception.expectMessage(incorrectName); exception.expectMessage(expectedCheckerMessage); - createVaadinController(endpointWithIllegalName, mock(ObjectMapper.class), - null, nameChecker, null); + createVaadinController(endpointWithIllegalName, + mock(ObjectMapper.class), null, nameChecker, null); } @Test @@ -236,8 +237,8 @@ public void should_Return404_When_MethodNotFound() { assertNotEquals(TEST_METHOD.getName(), missingEndpointMethod); ResponseEntity response = createVaadinController(TEST_ENDPOINT) - .serveEndpoint(TEST_ENDPOINT_NAME, missingEndpointMethod, - null, requestMock); + .serveEndpoint(TEST_ENDPOINT_NAME, missingEndpointMethod, null, + requestMock); assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); assertNull(response.getBody()); @@ -252,8 +253,7 @@ public void should_Return404_When_IllegalAccessToMethodIsPerformed() { when(restrictingCheckerMock.check(TEST_METHOD, requestMock)) .thenReturn(accessErrorMessage); - EndpointNameChecker nameCheckerMock = mock( - EndpointNameChecker.class); + EndpointNameChecker nameCheckerMock = mock(EndpointNameChecker.class); when(nameCheckerMock.check(TEST_ENDPOINT_NAME)).thenReturn(null); ExplicitNullableTypeChecker explicitNullableTypeCheckerMock = mock( @@ -261,9 +261,9 @@ public void should_Return404_When_IllegalAccessToMethodIsPerformed() { ResponseEntity response = createVaadinController(TEST_ENDPOINT, new ObjectMapper(), restrictingCheckerMock, nameCheckerMock, - explicitNullableTypeCheckerMock) - .serveEndpoint(TEST_ENDPOINT_NAME, - TEST_METHOD.getName(), null, requestMock); + explicitNullableTypeCheckerMock).serveEndpoint( + TEST_ENDPOINT_NAME, TEST_METHOD.getName(), null, + requestMock); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); String responseBody = response.getBody(); @@ -271,15 +271,18 @@ public void should_Return404_When_IllegalAccessToMethodIsPerformed() { assertTrue(String.format("Invalid response body: '%s'", responseBody), responseBody.contains(accessErrorMessage)); - verify(restrictingCheckerMock, only()).check(TEST_METHOD, requestMock); - verify(restrictingCheckerMock, times(1)).check(TEST_METHOD, requestMock); + verify(restrictingCheckerMock).enableCsrf(Mockito.anyBoolean()); + verify(restrictingCheckerMock).check(TEST_METHOD, requestMock); + Mockito.verifyNoMoreInteractions(restrictingCheckerMock); + verify(restrictingCheckerMock, times(1)).check(TEST_METHOD, + requestMock); } @Test public void should_Return400_When_LessParametersSpecified1() { ResponseEntity response = createVaadinController(TEST_ENDPOINT) - .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), - null, requestMock); + .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), null, + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -296,7 +299,8 @@ public void should_Return400_When_MoreParametersSpecified() { ResponseEntity response = createVaadinController(TEST_ENDPOINT) .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - "{\"value1\": 222, \"value2\": 333}"), requestMock); + "{\"value1\": 222, \"value2\": 333}"), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -312,7 +316,8 @@ public void should_Return400_When_MoreParametersSpecified() { public void should_Return400_When_IncorrectParameterTypesAreProvided() { ResponseEntity response = createVaadinController(TEST_ENDPOINT) .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), - createRequestParameters("{\"value\": [222]}"), requestMock); + createRequestParameters("{\"value\": [222]}"), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -351,6 +356,7 @@ public void should_CallMethodAnonymously_When_UserPrincipalIsNullAndAnonymousAll @Test public void should_NotCallMethod_When_a_CSRF_request() { + when(appConfig.isXsrfProtectionEnabled()).thenReturn(true); when(requestMock.getHeader("X-CSRF-Token")).thenReturn(null); VaadinConnectController vaadinController = createVaadinControllerWithoutPrincipal(); @@ -375,7 +381,8 @@ public void should_NotCallMethodAnonymously_When_UserPrincipalIsNotInRole() { createRequestParameters("{}"), requestMock); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); - assertTrue(response.getBody().contains("Unauthorized access to Vaadin endpoint")); + assertTrue(response.getBody() + .contains("Unauthorized access to Vaadin endpoint")); } @Test @@ -411,11 +418,12 @@ public void should_CallMethodAnonymously_When_AnonymousOverridesRoles() { public void should_NotCallMethod_When_DenyAll() { VaadinConnectController vaadinController = createVaadinControllerWithoutPrincipal(); ResponseEntity response = vaadinController.serveEndpoint( - TEST_ENDPOINT_NAME, "denyAll", - createRequestParameters("{}"), requestMock); + TEST_ENDPOINT_NAME, "denyAll", createRequestParameters("{}"), + requestMock); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); - assertTrue(response.getBody().contains("Anonymous access is not allowed")); + assertTrue( + response.getBody().contains("Anonymous access is not allowed")); } @Test @@ -437,10 +445,9 @@ public void should_clearVaadinRequestInsntace_after_EndpointCall() { VaadinConnectController vaadinController = createVaadinController( TEST_ENDPOINT, new VaadinConnectAccessChecker()); - vaadinController.serveEndpoint( - TEST_ENDPOINT_NAME, "getUserName", + vaadinController.serveEndpoint(TEST_ENDPOINT_NAME, "getUserName", createRequestParameters("{}"), requestMock); - + Assert.assertNull(CurrentInstance.get(VaadinRequest.class)); Assert.assertNull(VaadinRequest.getCurrent()); } @@ -451,8 +458,8 @@ public void should_Return400_When_EndpointMethodThrowsIllegalArgumentException() throws Exception { int inputValue = 222; - Method endpointMethodMock = createEndpointMethodMockThatThrows(inputValue, - new IllegalArgumentException("OOPS")); + Method endpointMethodMock = createEndpointMethodMockThatThrows( + inputValue, new IllegalArgumentException("OOPS")); VaadinConnectController controller = createVaadinController( TEST_ENDPOINT); @@ -462,7 +469,8 @@ public void should_Return400_When_EndpointMethodThrowsIllegalArgumentException() ResponseEntity response = controller.serveEndpoint( TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -481,8 +489,8 @@ public void should_Return500_When_EndpointMethodThrowsIllegalAccessException() throws Exception { int inputValue = 222; - Method endpointMethodMock = createEndpointMethodMockThatThrows(inputValue, - new IllegalAccessException("OOPS")); + Method endpointMethodMock = createEndpointMethodMockThatThrows( + inputValue, new IllegalAccessException("OOPS")); VaadinConnectController controller = createVaadinController( TEST_ENDPOINT); @@ -492,7 +500,8 @@ public void should_Return500_When_EndpointMethodThrowsIllegalAccessException() ResponseEntity response = controller.serveEndpoint( TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); @@ -511,8 +520,8 @@ public void should_Return500_When_EndpointMethodThrowsInvocationTargetException( throws Exception { int inputValue = 222; - Method endpointMethodMock = createEndpointMethodMockThatThrows(inputValue, - new InvocationTargetException( + Method endpointMethodMock = createEndpointMethodMockThatThrows( + inputValue, new InvocationTargetException( new IllegalStateException("OOPS"))); VaadinConnectController controller = createVaadinController( @@ -523,7 +532,8 @@ public void should_Return500_When_EndpointMethodThrowsInvocationTargetException( ResponseEntity response = controller.serveEndpoint( TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); @@ -543,8 +553,8 @@ public void should_Return400_When_EndpointMethodThrowsVaadinConnectException() int inputValue = 222; String expectedMessage = "OOPS"; - Method endpointMethodMock = createEndpointMethodMockThatThrows(inputValue, - new InvocationTargetException( + Method endpointMethodMock = createEndpointMethodMockThatThrows( + inputValue, new InvocationTargetException( new EndpointException(expectedMessage))); VaadinConnectController controller = createVaadinController( @@ -555,7 +565,8 @@ public void should_Return400_When_EndpointMethodThrowsVaadinConnectException() ResponseEntity response = controller.serveEndpoint( TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -581,7 +592,8 @@ public MyCustomException() { } } - Method endpointMethodMock = createEndpointMethodMockThatThrows(inputValue, + Method endpointMethodMock = createEndpointMethodMockThatThrows( + inputValue, new InvocationTargetException(new MyCustomException())); VaadinConnectController controller = createVaadinController( @@ -592,7 +604,8 @@ public MyCustomException() { ResponseEntity response = controller.serveEndpoint( TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); String responseBody = response.getBody(); @@ -627,7 +640,8 @@ public void should_Return500_When_MapperFailsToSerializeResponse() ResponseEntity response = createVaadinController(TEST_ENDPOINT, mapperMock).serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), - createRequestParameters("{\"value\": 222}"), requestMock); + createRequestParameters("{\"value\": 222}"), + requestMock); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); @@ -676,7 +690,8 @@ public void should_ReturnCorrectResponse_When_EverythingIsCorrect() { ResponseEntity response = createVaadinController(TEST_ENDPOINT) .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(String.format("\"%s\"", expectedOutput), @@ -689,25 +704,24 @@ public void should_ReturnCorrectResponse_When_EndpointClassIsProxied() { ApplicationContext contextMock = mock(ApplicationContext.class); TestClass endpoint = new TestClass(); TestClass proxy = mock(TestClass.class, CALLS_REAL_METHODS); - when(contextMock.getBeansWithAnnotation(Endpoint.class)) - .thenReturn(Collections.singletonMap( - endpoint.getClass().getSimpleName(), proxy)); + when(contextMock.getBeansWithAnnotation(Endpoint.class)).thenReturn( + Collections.singletonMap(endpoint.getClass().getSimpleName(), + proxy)); VaadinConnectController vaadinConnectController = new VaadinConnectController( new ObjectMapper(), mock(VaadinConnectAccessChecker.class), mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - contextMock, - mock(ServletContext.class)); + mock(ExplicitNullableTypeChecker.class), contextMock, + mockServletContext()); int inputValue = 222; String expectedOutput = endpoint.testMethod(inputValue); - ResponseEntity response = vaadinConnectController - .serveEndpoint("TestClass", "testMethod", - createRequestParameters( - String.format("{\"value\": %s}", inputValue)), - requestMock); + ResponseEntity response = vaadinConnectController.serveEndpoint( + "TestClass", "testMethod", + createRequestParameters( + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(String.format("\"%s\"", expectedOutput), @@ -722,8 +736,10 @@ public void should_NotUseBridgeMethod_When_EndpointHasBridgeMethodFromInterface( String testMethodName = "testMethodFromInterface"; ResponseEntity response = createVaadinController(testEndpoint) .serveEndpoint(testEndpoint.getClass().getSimpleName(), - testMethodName, createRequestParameters(String.format( - "{\"value\": {\"id\": \"%s\"}}", inputId)), requestMock); + testMethodName, + createRequestParameters(String.format( + "{\"value\": {\"id\": \"%s\"}}", inputId)), + requestMock); assertEquals(expectedResult, response.getBody()); } @@ -735,8 +751,10 @@ public void should_NotUseBridgeMethod_When_EndpointHasBridgeMethodFromParentClas ResponseEntity response = createVaadinController(testEndpoint) .serveEndpoint(testEndpoint.getClass().getSimpleName(), - testMethodName, createRequestParameters( - String.format("{\"value\": %s}", inputId)), requestMock); + testMethodName, + createRequestParameters( + String.format("{\"value\": %s}", inputId)), + requestMock); assertEquals(inputId, response.getBody()); } @@ -748,8 +766,10 @@ public void should_ReturnCorrectResponse_When_CallingNormalOverriddenMethod() { ResponseEntity response = createVaadinController(testEndpoint) .serveEndpoint(testEndpoint.getClass().getSimpleName(), - testMethodName, createRequestParameters( - String.format("{\"value\": %s}", inputId)), requestMock); + testMethodName, + createRequestParameters( + String.format("{\"value\": %s}", inputId)), + requestMock); assertEquals(inputId, response.getBody()); } @@ -768,13 +788,13 @@ public void should_UseCustomEndpointName_When_ItIsDefined() { VaadinConnectController vaadinConnectController = new VaadinConnectController( new ObjectMapper(), mock(VaadinConnectAccessChecker.class), mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - contextMock, - mock(ServletContext.class)); + mock(ExplicitNullableTypeChecker.class), contextMock, + mockServletContext()); ResponseEntity response = vaadinConnectController .serveEndpoint("CustomEndpoint", "testMethod", createRequestParameters( - String.format("{\"value\": %s}", input)), requestMock); + String.format("{\"value\": %s}", input)), + requestMock); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals(String.format("\"%s\"", expectedOutput), response.getBody()); @@ -787,16 +807,15 @@ public void should_UseCustomEndpointName_When_EndpointClassIsProxied() { TestClassWithCustomEndpointName endpoint = new TestClassWithCustomEndpointName(); TestClassWithCustomEndpointName proxy = mock( TestClassWithCustomEndpointName.class, CALLS_REAL_METHODS); - when(contextMock.getBeansWithAnnotation(Endpoint.class)) - .thenReturn(Collections.singletonMap( - endpoint.getClass().getSimpleName(), proxy)); + when(contextMock.getBeansWithAnnotation(Endpoint.class)).thenReturn( + Collections.singletonMap(endpoint.getClass().getSimpleName(), + proxy)); VaadinConnectController vaadinConnectController = new VaadinConnectController( new ObjectMapper(), mock(VaadinConnectAccessChecker.class), mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - contextMock, - mock(ServletContext.class)); + mock(ExplicitNullableTypeChecker.class), contextMock, + mockServletContext()); int input = 111; String expectedOutput = endpoint.testMethod(input); @@ -816,7 +835,8 @@ public void should_Never_UseSpringObjectMapper() { ApplicationContext contextMock = mock(ApplicationContext.class); ObjectMapper mockSpringObjectMapper = mock(ObjectMapper.class); ObjectMapper mockOwnObjectMapper = mock(ObjectMapper.class); - Jackson2ObjectMapperBuilder mockObjectMapperBuilder = mock(Jackson2ObjectMapperBuilder.class); + Jackson2ObjectMapperBuilder mockObjectMapperBuilder = mock( + Jackson2ObjectMapperBuilder.class); JacksonProperties mockJacksonProperties = mock(JacksonProperties.class); when(contextMock.getBean(ObjectMapper.class)) .thenReturn(mockSpringObjectMapper); @@ -826,19 +846,18 @@ public void should_Never_UseSpringObjectMapper() { .thenReturn(mockObjectMapperBuilder); when(mockObjectMapperBuilder.createXmlMapper(false)) .thenReturn(mockObjectMapperBuilder); - when(mockObjectMapperBuilder.build()) - .thenReturn(mockOwnObjectMapper); + when(mockObjectMapperBuilder.build()).thenReturn(mockOwnObjectMapper); when(mockJacksonProperties.getVisibility()) .thenReturn(Collections.emptyMap()); new VaadinConnectController(null, mock(VaadinConnectAccessChecker.class), mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - contextMock, - mock(ServletContext.class)); + mock(ExplicitNullableTypeChecker.class), contextMock, + mockServletContext()); verify(contextMock, never()).getBean(ObjectMapper.class); - verify(contextMock, times(1)).getBean(Jackson2ObjectMapperBuilder.class); + verify(contextMock, times(1)) + .getBean(Jackson2ObjectMapperBuilder.class); verify(contextMock, times(1)).getBean(JacksonProperties.class); verify(mockOwnObjectMapper, times(1)).setVisibility( PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); @@ -849,7 +868,8 @@ public void should_NotOverrideVisibility_When_JacksonPropertiesProvideVisibility ApplicationContext contextMock = mock(ApplicationContext.class); ObjectMapper mockDefaultObjectMapper = mock(ObjectMapper.class); ObjectMapper mockOwnObjectMapper = mock(ObjectMapper.class); - Jackson2ObjectMapperBuilder mockObjectMapperBuilder = mock(Jackson2ObjectMapperBuilder.class); + Jackson2ObjectMapperBuilder mockObjectMapperBuilder = mock( + Jackson2ObjectMapperBuilder.class); JacksonProperties mockJacksonProperties = mock(JacksonProperties.class); when(contextMock.getBean(ObjectMapper.class)) .thenReturn(mockDefaultObjectMapper); @@ -859,24 +879,23 @@ public void should_NotOverrideVisibility_When_JacksonPropertiesProvideVisibility .thenReturn(mockObjectMapperBuilder); when(mockObjectMapperBuilder.createXmlMapper(false)) .thenReturn(mockObjectMapperBuilder); - when(mockObjectMapperBuilder.build()) - .thenReturn(mockOwnObjectMapper); + when(mockObjectMapperBuilder.build()).thenReturn(mockOwnObjectMapper); when(mockJacksonProperties.getVisibility()) .thenReturn(Collections.singletonMap(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY)); new VaadinConnectController(null, mock(VaadinConnectAccessChecker.class), mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - contextMock, - mock(ServletContext.class)); + mock(ExplicitNullableTypeChecker.class), contextMock, + mockServletContext()); verify(contextMock, never()).getBean(ObjectMapper.class); - verify(contextMock, times(1)).getBean(Jackson2ObjectMapperBuilder.class); + verify(contextMock, times(1)) + .getBean(Jackson2ObjectMapperBuilder.class); verify(mockDefaultObjectMapper, never()).setVisibility( PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); - verify(mockOwnObjectMapper, never()).setVisibility( - PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + verify(mockOwnObjectMapper, never()).setVisibility(PropertyAccessor.ALL, + JsonAutoDetect.Visibility.ANY); verify(contextMock, times(1)).getBean(JacksonProperties.class); } @@ -890,7 +909,8 @@ public void should_ReturnValidationError_When_DeserializationFails() ResponseEntity response = createVaadinController(TEST_ENDPOINT) .serveEndpoint(TEST_ENDPOINT_NAME, TEST_METHOD.getName(), createRequestParameters( - String.format("{\"value\": %s}", inputValue)), requestMock); + String.format("{\"value\": %s}", inputValue)), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); ObjectNode jsonNodes = new ObjectMapper().readValue(response.getBody(), @@ -950,7 +970,8 @@ public void should_ReturnValidationError_When_EndpointMethodParameterIsInvalid() ResponseEntity response = createVaadinController(TEST_ENDPOINT) .serveEndpoint(TEST_ENDPOINT_NAME, TEST_VALIDATION_METHOD.getName(), - createRequestParameters("{\"parameter\": null}"), requestMock); + createRequestParameters("{\"parameter\": null}"), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); ObjectNode jsonNodes = new ObjectMapper().readValue(response.getBody(), @@ -988,7 +1009,8 @@ public void should_ReturnValidationError_When_EndpointMethodBeanIsInvalid() TEST_VALIDATION_METHOD.getName(), createRequestParameters(String.format( "{\"parameter\": {\"count\": %d}}", - invalidPropertyValue)), requestMock); + invalidPropertyValue)), + requestMock); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); ObjectNode jsonNodes = new ObjectMapper().readValue(response.getBody(), @@ -1019,8 +1041,7 @@ public void should_Invoke_ExplicitNullableTypeChecker() ExplicitNullableTypeChecker.class); when(explicitNullableTypeChecker.checkValueForType( - eq(NullCheckerTestClass.OK_RESPONSE), - eq(String.class))) + eq(NullCheckerTestClass.OK_RESPONSE), eq(String.class))) .thenReturn(null); String testOkMethod = "testOkMethod"; @@ -1051,20 +1072,20 @@ public void should_ReturnException_When_ExplicitNullableTypeChecker_ReturnsError Method testNullMethod = NullCheckerTestClass.class .getMethod(testNullMethodName); when(explicitNullableTypeChecker.checkValueForAnnotatedElement(null, - testNullMethod)) - .thenReturn(errorMessage); + testNullMethod)).thenReturn(errorMessage); ResponseEntity response = createVaadinController( new NullCheckerTestClass(), null, null, null, explicitNullableTypeChecker).serveEndpoint( NullCheckerTestClass.class.getSimpleName(), - testNullMethodName, createRequestParameters("{}"), + testNullMethodName, createRequestParameters("{}"), requestMock); verify(explicitNullableTypeChecker).checkValueForAnnotatedElement(null, testNullMethod); - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, + response.getStatusCode()); ObjectNode jsonNodes = new ObjectMapper().readValue(response.getBody(), ObjectNode.class); @@ -1072,31 +1093,41 @@ testNullMethodName, createRequestParameters("{}"), jsonNodes.get("type").asText()); final String message = jsonNodes.get("message").asText(); assertTrue(message.contains("Unexpected return value")); - assertTrue(message.contains(NullCheckerTestClass.class.getSimpleName())); + assertTrue( + message.contains(NullCheckerTestClass.class.getSimpleName())); assertTrue(message.contains(testNullMethodName)); assertTrue(message.contains(errorMessage)); } @Test public void should_ReturnResult_When_CallingSuperClassMethodWithGenericTypedParameter() { - ResponseEntity response = createVaadinController(new PersonEndpoint()) - .serveEndpoint(PersonEndpoint.class.getSimpleName(), "update", - createRequestParameters( - "{\"entity\":{\"name\":\"aa\"}}"), requestMock); + ResponseEntity response = createVaadinController( + new PersonEndpoint()) + .serveEndpoint(PersonEndpoint.class.getSimpleName(), + "update", + createRequestParameters( + "{\"entity\":{\"name\":\"aa\"}}"), + requestMock); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("{\"name\":\"aa\"}", response.getBody()); } @Test - public void should_AllowAccessToPackagePrivateEndpoint_PublicMethods() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { - Class packagePrivateEndpoint = Class.forName("com.vaadin.flow.server.connect.generator.endpoints.packageprivate.PackagePrivateEndpoint"); - Constructor packagePrivateEndpointConstructor = packagePrivateEndpoint.getConstructor(); + public void should_AllowAccessToPackagePrivateEndpoint_PublicMethods() + throws ClassNotFoundException, NoSuchMethodException, + IllegalAccessException, InvocationTargetException, + InstantiationException { + Class packagePrivateEndpoint = Class.forName( + "com.vaadin.flow.server.connect.generator.endpoints.packageprivate.PackagePrivateEndpoint"); + Constructor packagePrivateEndpointConstructor = packagePrivateEndpoint + .getConstructor(); packagePrivateEndpointConstructor.setAccessible(true); - ResponseEntity response = createVaadinController(packagePrivateEndpointConstructor.newInstance()) - .serveEndpoint("PackagePrivateEndpoint", "getRequest", - createRequestParameters("{}"), requestMock); + ResponseEntity response = createVaadinController( + packagePrivateEndpointConstructor.newInstance()).serveEndpoint( + "PackagePrivateEndpoint", "getRequest", + createRequestParameters("{}"), requestMock); assertEquals(HttpStatus.OK, response.getStatusCode()); assertEquals("\"Hello\"", response.getBody()); @@ -1126,12 +1157,14 @@ private VaadinConnectController createVaadinController(T endpoint) { private VaadinConnectController createVaadinController(T endpoint, ObjectMapper vaadinEndpointMapper) { - return createVaadinController(endpoint, vaadinEndpointMapper, null, null, null); + return createVaadinController(endpoint, vaadinEndpointMapper, null, + null, null); } private VaadinConnectController createVaadinController(T endpoint, VaadinConnectAccessChecker accessChecker) { - return createVaadinController(endpoint, null, accessChecker, null, null); + return createVaadinController(endpoint, null, accessChecker, null, + null); } private VaadinConnectController createVaadinController(T endpoint, @@ -1142,23 +1175,23 @@ private VaadinConnectController createVaadinController(T endpoint, Class endpointClass = endpoint.getClass(); ApplicationContext contextMock = mock(ApplicationContext.class); - when(contextMock.getBeansWithAnnotation(Endpoint.class)) - .thenReturn(Collections.singletonMap(endpointClass.getName(), - endpoint)); + when(contextMock.getBeansWithAnnotation(Endpoint.class)).thenReturn( + Collections.singletonMap(endpointClass.getName(), endpoint)); if (vaadinEndpointMapper == null) { vaadinEndpointMapper = new ObjectMapper(); } if (accessChecker == null) { - accessChecker = mock( - VaadinConnectAccessChecker.class); - when(accessChecker.check(TEST_METHOD, requestMock)).thenReturn(null); + accessChecker = mock(VaadinConnectAccessChecker.class); + when(accessChecker.check(TEST_METHOD, requestMock)) + .thenReturn(null); } if (endpointNameChecker == null) { endpointNameChecker = mock(EndpointNameChecker.class); - when(endpointNameChecker.check(TEST_ENDPOINT_NAME)).thenReturn(null); + when(endpointNameChecker.check(TEST_ENDPOINT_NAME)) + .thenReturn(null); } if (explicitNullableTypeChecker == null) { @@ -1168,15 +1201,17 @@ private VaadinConnectController createVaadinController(T endpoint, .thenReturn(null); } + ServletContext servletContext = mockServletContext(); + return new VaadinConnectController(vaadinEndpointMapper, accessChecker, - endpointNameChecker, explicitNullableTypeChecker, - contextMock, - mock(ServletContext.class)); + endpointNameChecker, explicitNullableTypeChecker, contextMock, + servletContext); } private VaadinConnectController createVaadinControllerWithoutPrincipal() { when(requestMock.getUserPrincipal()).thenReturn(null); - return createVaadinController(TEST_ENDPOINT, new VaadinConnectAccessChecker()); + return createVaadinController(TEST_ENDPOINT, + new VaadinConnectAccessChecker()); } private Method createEndpointMethodMockThatThrows(Object argument, @@ -1193,4 +1228,12 @@ private Method createEndpointMethodMockThatThrows(Object argument, when(endpointMethodMock.getName()).thenReturn(TEST_METHOD.getName()); return endpointMethodMock; } + + private ServletContext mockServletContext() { + ServletContext context = Mockito.mock(ServletContext.class); + Mockito.when( + context.getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + return context; + } } diff --git a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/rest/EndpointWithRestControllerTest.java b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/rest/EndpointWithRestControllerTest.java index 976f6ad6984..e6cb05270be 100644 --- a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/rest/EndpointWithRestControllerTest.java +++ b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/rest/EndpointWithRestControllerTest.java @@ -22,6 +22,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.ApplicationContext; @@ -37,6 +38,7 @@ import com.vaadin.flow.server.connect.ExplicitNullableTypeChecker; import com.vaadin.flow.server.connect.VaadinConnectController; import com.vaadin.flow.server.connect.auth.VaadinConnectAccessChecker; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -48,7 +50,7 @@ @RunWith(SpringRunner.class) @WebMvcTest -@Import({VaadinConnectEndpoints.class, MyRestController.class}) +@Import({ VaadinConnectEndpoints.class, MyRestController.class }) public class EndpointWithRestControllerTest { private MockMvc mockMvcForEndpoint; @@ -56,71 +58,81 @@ public class EndpointWithRestControllerTest { @Autowired private MockMvc mockMvcForRest; - @Autowired private ApplicationContext applicationContext; + private ApplicationConfiguration appConfig; + @Before public void setUp() { - mockMvcForEndpoint = MockMvcBuilders.standaloneSetup(new VaadinConnectController( - null, mock(VaadinConnectAccessChecker.class), - mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - applicationContext, - mock(ServletContext.class))) + appConfig = Mockito.mock(ApplicationConfiguration.class); + + mockMvcForEndpoint = MockMvcBuilders + .standaloneSetup(new VaadinConnectController(null, + mock(VaadinConnectAccessChecker.class), + mock(EndpointNameChecker.class), + mock(ExplicitNullableTypeChecker.class), + applicationContext, mockServletContext())) .build(); Assert.assertNotEquals(null, applicationContext); } @Test - //https://github.com/vaadin/flow/issues/8010 + // https://github.com/vaadin/flow/issues/8010 public void shouldNotExposePrivateAndProtectedFields_when_CallingFromRestAPIs() - throws Exception { - String result = mockMvcForRest.perform(get("/api/get") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andReturn().getResponse().getContentAsString(); + throws Exception { + String result = mockMvcForRest + .perform( + get("/api/get").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn().getResponse() + .getContentAsString(); assertEquals("{\"name\":\"Bond\"}", result); } @Test - //https://github.com/vaadin/flow/issues/8034 + // https://github.com/vaadin/flow/issues/8034 public void should_BeAbleToSerializePrivateFieldsOfABean_when_CallingFromConnectEndPoint() { try { String result = callEndpointMethod("getBeanWithPrivateFields"); - assertEquals("{\"codeNumber\":\"007\",\"name\":\"Bond\",\"firstName\":\"James\"}", result); + assertEquals( + "{\"codeNumber\":\"007\",\"name\":\"Bond\",\"firstName\":\"James\"}", + result); } catch (Exception e) { fail("failed to serialize a bean with private fields"); } } @Test - //https://github.com/vaadin/flow/issues/8034 + // https://github.com/vaadin/flow/issues/8034 public void should_BeAbleToSerializeABeanWithZonedDateTimeField() { try { String result = callEndpointMethod("getBeanWithZonedDateTimeField"); assertNotNull(result); assertNotEquals("", result); - assertNotEquals("{\"message\":\"Failed to serialize endpoint 'VaadinConnectTypeConversionEndpoints' method 'getBeanWithZonedDateTimeField' response. Double check method's return type or specify a custom mapper bean with qualifier 'vaadinEndpointMapper'\"}", result); + assertNotEquals( + "{\"message\":\"Failed to serialize endpoint 'VaadinConnectTypeConversionEndpoints' method 'getBeanWithZonedDateTimeField' response. Double check method's return type or specify a custom mapper bean with qualifier 'vaadinEndpointMapper'\"}", + result); } catch (Exception e) { fail("failed to serialize a bean with ZonedDateTime field"); } } @Test - //https://github.com/vaadin/flow/issues/8067 - public void should_RepsectJacksonAnnotation_when_serializeBean() throws Exception { + // https://github.com/vaadin/flow/issues/8067 + public void should_RepsectJacksonAnnotation_when_serializeBean() + throws Exception { String result = callEndpointMethod("getBeanWithJacksonAnnotation"); assertEquals("{\"name\":null,\"rating\":2,\"bookId\":null}", result); } @Test /** - * this requires jackson-datatype-jsr310, which is added as a test scope dependency. - * jackson-datatype-jsr310 is provided in spring-boot-starter-web, which is part of - * vaadin-spring-boot-starter + * this requires jackson-datatype-jsr310, which is added as a test scope + * dependency. jackson-datatype-jsr310 is provided in + * spring-boot-starter-web, which is part of vaadin-spring-boot-starter */ - public void should_serializeLocalTimeInExpectedFormat_when_UsingSpringBoot() throws Exception{ + public void should_serializeLocalTimeInExpectedFormat_when_UsingSpringBoot() + throws Exception { String result = callEndpointMethod("getLocalTime"); assertEquals("\"08:00:00\"", result); } @@ -132,7 +144,15 @@ private String callEndpointMethod(String methodName) throws Exception { .accept(MediaType.APPLICATION_JSON_UTF8_VALUE) .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE); - return mockMvcForEndpoint.perform(requestBuilder).andReturn().getResponse().getContentAsString(); + return mockMvcForEndpoint.perform(requestBuilder).andReturn() + .getResponse().getContentAsString(); } -} + private ServletContext mockServletContext() { + ServletContext context = Mockito.mock(ServletContext.class); + Mockito.when( + context.getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + return context; + } +} diff --git a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/typeconversion/BaseTypeConversionTest.java b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/typeconversion/BaseTypeConversionTest.java index 388d56426cc..309a08e86be 100644 --- a/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/typeconversion/BaseTypeConversionTest.java +++ b/fusion-endpoint/src/test/java/com/vaadin/flow/server/connect/typeconversion/BaseTypeConversionTest.java @@ -20,6 +20,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.ApplicationContext; @@ -32,10 +33,11 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import com.vaadin.flow.server.connect.ExplicitNullableTypeChecker; import com.vaadin.flow.server.connect.EndpointNameChecker; +import com.vaadin.flow.server.connect.ExplicitNullableTypeChecker; import com.vaadin.flow.server.connect.VaadinConnectController; import com.vaadin.flow.server.connect.auth.VaadinConnectAccessChecker; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import static org.mockito.Mockito.mock; @@ -49,14 +51,18 @@ public abstract class BaseTypeConversionTest { @Autowired private ApplicationContext applicationContext; + private ApplicationConfiguration appConfig; + @Before public void setUp() { - mockMvc = MockMvcBuilders.standaloneSetup(new VaadinConnectController( - null, mock(VaadinConnectAccessChecker.class), - mock(EndpointNameChecker.class), - mock(ExplicitNullableTypeChecker.class), - applicationContext, - mock(ServletContext.class))) + appConfig = Mockito.mock(ApplicationConfiguration.class); + + mockMvc = MockMvcBuilders + .standaloneSetup(new VaadinConnectController(null, + mock(VaadinConnectAccessChecker.class), + mock(EndpointNameChecker.class), + mock(ExplicitNullableTypeChecker.class), + applicationContext, mockServletContext())) .build(); Assert.assertNotEquals(null, applicationContext); } @@ -95,4 +101,12 @@ protected MockHttpServletResponse callMethod(String methodName, .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE); return mockMvc.perform(requestBuilder).andReturn().getResponse(); } + + private ServletContext mockServletContext() { + ServletContext context = Mockito.mock(ServletContext.class); + Mockito.when( + context.getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + return context; + } } diff --git a/fusion-endpoint/src/test/java/com/vaadin/flow/server/startup/fusion/DevModeInitializerEndpointTest.java b/fusion-endpoint/src/test/java/com/vaadin/flow/server/startup/fusion/DevModeInitializerEndpointTest.java index fad55352d93..1f8a6abcfcb 100644 --- a/fusion-endpoint/src/test/java/com/vaadin/flow/server/startup/fusion/DevModeInitializerEndpointTest.java +++ b/fusion-endpoint/src/test/java/com/vaadin/flow/server/startup/fusion/DevModeInitializerEndpointTest.java @@ -1,14 +1,7 @@ package com.vaadin.flow.server.startup.fusion; -import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; -import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; -import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_GENERATED_TS_DIR; -import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_JAVA_SOURCE_FOLDER; -import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_OPENAPI_JSON_FILE; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import javax.servlet.ServletContext; +import javax.servlet.ServletRegistration; import java.io.File; import java.lang.reflect.InvocationTargetException; @@ -21,8 +14,14 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; +import net.jcip.annotations.NotThreadSafe; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.mockito.Mockito; import com.vaadin.flow.di.Lookup; import com.vaadin.flow.di.ResourceProvider; @@ -31,27 +30,28 @@ import com.vaadin.flow.server.frontend.EndpointGeneratorTaskFactory; import com.vaadin.flow.server.frontend.FrontendUtils; import com.vaadin.flow.server.frontend.fusion.EndpointGeneratorTaskFactoryImpl; +import com.vaadin.flow.server.startup.ApplicationConfiguration; import com.vaadin.flow.server.startup.DevModeInitializer; -import org.apache.commons.io.FileUtils; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.mockito.Mockito; - -import net.jcip.annotations.NotThreadSafe; +import static com.vaadin.flow.server.Constants.CONNECT_JAVA_SOURCE_FOLDER_TOKEN; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_PRODUCTION_MODE; +import static com.vaadin.flow.server.InitParameters.SERVLET_PARAMETER_REUSE_DEV_SERVER; +import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_GENERATED_TS_DIR; +import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_JAVA_SOURCE_FOLDER; +import static com.vaadin.flow.server.frontend.FrontendUtils.DEFAULT_CONNECT_OPENAPI_JSON_FILE; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @NotThreadSafe public class DevModeInitializerEndpointTest { private final AtomicReference atomicHandler = new AtomicReference<>(); - + String baseDir; ServletContext servletContext; - Map initParams; Set> classes; DevModeInitializer devModeInitializer; + private ApplicationConfiguration appConfig; private final TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -67,14 +67,24 @@ public void setup() throws Exception { temporaryFolder.create(); baseDir = temporaryFolder.getRoot().getPath(); - servletContext = Mockito.mock(ServletContext.class); + appConfig = Mockito.mock(ApplicationConfiguration.class); + Mockito.when(appConfig.getStringProperty(Mockito.anyString(), + Mockito.anyString())) + .thenAnswer(invocation -> invocation.getArgumentAt(1, + String.class)); + Mockito.when(appConfig.getStringProperty(FrontendUtils.PROJECT_BASEDIR, + null)).thenReturn(baseDir); + Mockito.when(appConfig.enableDevServer()).thenReturn(true); + + servletContext = mockServletContext(); ServletRegistration vaadinServletRegistration = Mockito .mock(ServletRegistration.class); Lookup lookup = Mockito.mock(Lookup.class); Mockito.when(servletContext.getAttribute(Lookup.class.getName())) .thenReturn(lookup); - Mockito.doReturn(new EndpointGeneratorTaskFactoryImpl()).when(lookup).lookup(EndpointGeneratorTaskFactory.class); + Mockito.doReturn(new EndpointGeneratorTaskFactoryImpl()).when(lookup) + .lookup(EndpointGeneratorTaskFactory.class); ResourceProvider resourceProvider = Mockito .mock(ResourceProvider.class); @@ -84,12 +94,6 @@ public void setup() throws Exception { Mockito.when(vaadinServletRegistration.getClassName()) .thenReturn(VaadinServletSubClass.class.getName()); - initParams = new HashMap<>(); - initParams.put(FrontendUtils.PROJECT_BASEDIR, baseDir); - - Mockito.when(vaadinServletRegistration.getInitParameters()) - .thenReturn(initParams); - classes = new HashSet<>(); classes.add(this.getClass()); @@ -128,105 +132,61 @@ public void teardown() throws Exception, SecurityException { @Test public void should_generateOpenApi_when_EndpointPresents() throws Exception { - String originalJavaSourceFolder = null; File generatedOpenApiJson = Paths - .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); - try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - // Configure a folder that has .java classes with valid endpoints - // Not using `src/test/java` because there are invalid endpoint names - // in some tests - File src = new File( - getClass().getClassLoader().getResource("java").getFile()); - System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, - src.getAbsolutePath()); - - Assert.assertFalse(generatedOpenApiJson.exists()); - DevModeInitializer devModeInitializer = new DevModeInitializer(); - devModeInitializer.onStartup(classes, servletContext); - waitForDevModeServer(); - Thread.sleep(200); - Assert.assertTrue("Should generate OpenAPI spec if Endpoint is used.", - generatedOpenApiJson.exists()); - } finally { - if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); - } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - } - generatedOpenApiJson.delete(); - } + .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); + File src = new File( + getClass().getClassLoader().getResource("java").getFile()); + Mockito.when(appConfig.getStringProperty( + Mockito.eq(CONNECT_JAVA_SOURCE_FOLDER_TOKEN), + Mockito.anyString())).thenReturn(src.getAbsolutePath()); + + Assert.assertFalse(generatedOpenApiJson.exists()); + DevModeInitializer devModeInitializer = new DevModeInitializer(); + devModeInitializer.process(classes, servletContext); + waitForDevModeServer(); + Thread.sleep(200); + Assert.assertTrue("Should generate OpenAPI spec if Endpoint is used.", + generatedOpenApiJson.exists()); } @Test public void should_notGenerateOpenApi_when_EndpointIsNotUsed() throws Exception { - String originalJavaSourceFolder = null; File generatedOpenApiJson = Paths .get(baseDir, DEFAULT_CONNECT_OPENAPI_JSON_FILE).toFile(); - try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - - Assert.assertFalse(generatedOpenApiJson.exists()); - devModeInitializer.onStartup(classes, servletContext); - Assert.assertFalse( + + Assert.assertFalse(generatedOpenApiJson.exists()); + devModeInitializer.process(classes, servletContext); + Assert.assertFalse( "Should not generate OpenAPI spec if Endpoint is not used.", generatedOpenApiJson.exists()); - } finally { - if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); - } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - } - generatedOpenApiJson.delete(); - } } @Test public void should_generateTs_files() throws Exception { - String originalJavaSourceFolder = null; - try { - originalJavaSourceFolder = System.getProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - // Configure a folder that has .java classes with valid endpoints - // Not using `src/test/java` because there are invalid endpoint names - // in some tests - File src = new File( - getClass().getClassLoader().getResource("java").getFile()); - System.setProperty("vaadin." + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, - src.getAbsolutePath()); - - DevModeInitializer devModeInitializer = new DevModeInitializer(); - - File ts1 = new File(baseDir, - DEFAULT_CONNECT_GENERATED_TS_DIR + "MyEndpoint.ts"); - File ts2 = new File(baseDir, DEFAULT_CONNECT_GENERATED_TS_DIR - + "connect-client.default.ts"); - - assertFalse(ts1.exists()); - assertFalse(ts2.exists()); - devModeInitializer.onStartup(classes, servletContext); - waitForDevModeServer(); - assertTrue(ts1.exists()); - assertTrue(ts2.exists()); - } finally { - if (originalJavaSourceFolder != null) { - System.setProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN, originalJavaSourceFolder); - } else { - System.clearProperty("vaadin." - + CONNECT_JAVA_SOURCE_FOLDER_TOKEN); - } - } + // Configure a folder that has .java classes with valid endpoints + // Not using `src/test/java` because there are invalid endpoint + // names + // in some tests + File src = new File( + getClass().getClassLoader().getResource("java").getFile()); + Mockito.when(appConfig.getStringProperty( + Mockito.eq(CONNECT_JAVA_SOURCE_FOLDER_TOKEN), + Mockito.anyString())).thenReturn(src.getAbsolutePath()); + + DevModeInitializer devModeInitializer = new DevModeInitializer(); + + File ts1 = new File(baseDir, + DEFAULT_CONNECT_GENERATED_TS_DIR + "MyEndpoint.ts"); + File ts2 = new File(baseDir, + DEFAULT_CONNECT_GENERATED_TS_DIR + "connect-client.default.ts"); + + assertFalse(ts1.exists()); + assertFalse(ts2.exists()); + devModeInitializer.process(classes, servletContext); + waitForDevModeServer(); + assertTrue(ts1.exists()); + assertTrue(ts2.exists()); } /** @@ -235,11 +195,12 @@ public void should_generateTs_files() throws Exception { * @return devModeHandler or {@code null} if not started */ private DevModeHandler getDevModeHandler() { - return atomicHandler.get(); + return atomicHandler.get(); } - private void waitForDevModeServer() throws NoSuchMethodException, - IllegalAccessException, InvocationTargetException, InterruptedException { + private void waitForDevModeServer() + throws NoSuchMethodException, IllegalAccessException, + InvocationTargetException, InterruptedException { DevModeHandler handler = DevModeHandler.getDevModeHandler(); Assert.assertNotNull(handler); Method join = DevModeHandler.class.getDeclaredMethod("join"); @@ -247,4 +208,12 @@ private void waitForDevModeServer() throws NoSuchMethodException, join.invoke(handler); } + private ServletContext mockServletContext() { + ServletContext context = Mockito.mock(ServletContext.class); + Mockito.when( + context.getAttribute(ApplicationConfiguration.class.getName())) + .thenReturn(appConfig); + return context; + } + } From 5b4d5df310290e51dcb5002fe1f6bd6083526b20 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 18 Dec 2020 10:16:35 +0300 Subject: [PATCH 25/32] fix: correct "createDeploymentConfiguration" code impl --- .../src/main/java/com/vaadin/flow/server/VaadinServlet.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java index 26fb2c36fd1..a1c4bfe82a4 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java @@ -203,9 +203,11 @@ protected DeploymentConfiguration createDeploymentConfiguration() */ protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { + VaadinServletContext context = new VaadinServletContext( + getServletContext()); return new DefaultDeploymentConfiguration( - ApplicationConfiguration.get(getService().getContext()), - getClass(), initParameters); + ApplicationConfiguration.get(context), getClass(), + initParameters); } /** From aba867a39c618955079ae366641ad7e4f71ffc25 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 18 Dec 2020 10:54:27 +0300 Subject: [PATCH 26/32] fix: yet another fix for createDeploymentConfiguration impl --- .../vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java index 0a0242a4f96..c3effc31786 100644 --- a/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java +++ b/flow-tests/test-root-ui-context/src/main/java/com/vaadin/flow/uitest/servlet/ApplicationRunnerServlet.java @@ -58,6 +58,7 @@ import com.vaadin.flow.server.SystemMessagesProvider; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinServlet; +import com.vaadin.flow.server.VaadinServletContext; import com.vaadin.flow.server.VaadinServletRequest; import com.vaadin.flow.server.VaadinServletService; import com.vaadin.flow.server.VaadinSession; @@ -246,7 +247,8 @@ protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { // Get the original configuration from the super class final DeploymentConfiguration originalConfiguration = new DefaultDeploymentConfiguration( - ApplicationConfiguration.get(getService().getContext()), + ApplicationConfiguration + .get(new VaadinServletContext(getServletContext())), getClass(), initParameters) { @Override public String getUIClassName() { From a221f98453baa170f2e2a501bd2dda6764b698c5 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Fri, 18 Dec 2020 11:34:28 +0300 Subject: [PATCH 27/32] fix: rewrite UI IT to avoid removed annotation --- .../com/vaadin/flow/memoryleaks/ui/MemoryLeakUI.java | 10 ++++++---- .../com/vaadin/flow/test/scalability/HelloWorldUI.java | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/flow-tests/test-memory-leaks/src/main/java/com/vaadin/flow/memoryleaks/ui/MemoryLeakUI.java b/flow-tests/test-memory-leaks/src/main/java/com/vaadin/flow/memoryleaks/ui/MemoryLeakUI.java index e89fb55105a..ae850a5d958 100644 --- a/flow-tests/test-memory-leaks/src/main/java/com/vaadin/flow/memoryleaks/ui/MemoryLeakUI.java +++ b/flow-tests/test-memory-leaks/src/main/java/com/vaadin/flow/memoryleaks/ui/MemoryLeakUI.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.memoryleaks.ui; +import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import com.vaadin.flow.component.Text; @@ -22,19 +23,20 @@ import com.vaadin.flow.component.html.NativeButton; import com.vaadin.flow.server.VaadinRequest; import com.vaadin.flow.server.VaadinServlet; -import com.vaadin.flow.server.VaadinServletConfiguration; public class MemoryLeakUI extends UI { - @WebServlet(asyncSupported = true, urlPatterns = { "/*" }) - @VaadinServletConfiguration(productionMode = false, ui = MemoryLeakUI.class) + @WebServlet(asyncSupported = true, urlPatterns = "/*", initParams = { + @WebInitParam(name = "ui", value = "com.vaadin.flow.memoryleaks.ui.MemoryLeakUI"), + @WebInitParam(name = "productionMode", value = "false") }) public static class MemoryLeakServlet extends VaadinServlet { } @Override protected void init(VaadinRequest request) { - NativeButton button = new NativeButton("Hello", e -> add(new Text("Hello"))); + NativeButton button = new NativeButton("Hello", + e -> add(new Text("Hello"))); button.setId("hello"); add(button); } diff --git a/flow-tests/test-scalability/src/main/java/com/vaadin/flow/test/scalability/HelloWorldUI.java b/flow-tests/test-scalability/src/main/java/com/vaadin/flow/test/scalability/HelloWorldUI.java index c86a579eb4c..214b4506155 100644 --- a/flow-tests/test-scalability/src/main/java/com/vaadin/flow/test/scalability/HelloWorldUI.java +++ b/flow-tests/test-scalability/src/main/java/com/vaadin/flow/test/scalability/HelloWorldUI.java @@ -1,5 +1,6 @@ package com.vaadin.flow.test.scalability; +import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import com.vaadin.flow.component.Text; @@ -7,7 +8,6 @@ import com.vaadin.flow.component.html.NativeButton; import com.vaadin.flow.server.VaadinRequest; import com.vaadin.flow.server.VaadinServlet; -import com.vaadin.flow.server.VaadinServletConfiguration; /* * Copyright 2000-2020 Vaadin Ltd. @@ -29,12 +29,15 @@ public class HelloWorldUI extends UI { public static final String PATH = "/helloworld/"; + public static final String HELLO_WORLD_UI = HelloWorldUI.class.getName(); + /** * The main servlet for the application. */ @WebServlet(urlPatterns = PATH - + "*", name = "UIServlet", asyncSupported = true) - @VaadinServletConfiguration(ui = HelloWorldUI.class, productionMode = false) + + "*", name = "UIServlet", asyncSupported = true, initParams = { + @WebInitParam(name = "ui", value = "com.vaadin.flow.test.scalability.HelloWorldUI"), + @WebInitParam(name = "productionMode", value = "false") }) public static class Servlet extends VaadinServlet { } From 83850593eba38a8ae131bf595e0a69461e3f49c8 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Sat, 19 Dec 2020 17:20:00 +0300 Subject: [PATCH 28/32] fix: SQ fixes --- .../vaadin/flow/server/DefaultDeploymentConfiguration.java | 4 +++- .../vaadin/flow/server/DeploymentConfigurationFactory.java | 6 ------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java index 7bb225cf919..29123eb77d0 100755 --- a/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DefaultDeploymentConfiguration.java @@ -122,7 +122,9 @@ public class DefaultDeploymentConfiguration /** * Create a new deployment configuration instance. - * + * + * @param parentConfig + * a parent application configuration * @param systemPropertyBaseClass * the class that should be used as a basis when reading system * properties diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index 14ae4a835b9..d3a55610945 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -21,9 +21,6 @@ import java.util.Map; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.vaadin.flow.component.UI; import com.vaadin.flow.function.DeploymentConfiguration; import com.vaadin.flow.server.frontend.FallbackChunk; @@ -50,9 +47,6 @@ public class DeploymentConfigurationFactory extends AbstractConfigurationFactory + "the project/working directory. Ensure 'webpack.config.js' is present or trigger creation of " + "'flow-build-info.json' via running 'prepare-frontend' Maven goal."; - private static final Logger logger = LoggerFactory - .getLogger(DeploymentConfigurationFactory.class); - /** * Creates a {@link DeploymentConfiguration} instance that is filled with * all parameters, specified for the current app. From 638e0c86d5bfbf1738743be05cd96ae9777125a6 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Sat, 19 Dec 2020 17:25:29 +0300 Subject: [PATCH 29/32] fix: get rid of exception which is never thrown anymore --- .../DeploymentConfigurationFactory.java | 15 ++++---- .../server/VaadinConfigurationException.java | 35 ------------------- .../com/vaadin/flow/server/VaadinServlet.java | 13 +++---- .../flow/server/startup/ServletDeployer.java | 29 +++++---------- .../DeploymentConfigurationFactoryTest.java | 7 ++-- ...ltApplicationConfigurationFactoryTest.java | 8 ++--- 6 files changed, 24 insertions(+), 83 deletions(-) delete mode 100644 flow-server/src/main/java/com/vaadin/flow/server/VaadinConfigurationException.java diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index d3a55610945..4a414799798 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -60,8 +60,7 @@ public class DeploymentConfigurationFactory extends AbstractConfigurationFactory * thrown if property construction fails */ public DeploymentConfiguration createDeploymentConfiguration( - Class systemPropertyBaseClass, VaadinConfig vaadinConfig) - throws VaadinConfigurationException { + Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { return new DefaultDeploymentConfiguration( ApplicationConfiguration.get(vaadinConfig.getVaadinContext()), systemPropertyBaseClass, @@ -82,8 +81,7 @@ public DeploymentConfiguration createDeploymentConfiguration( * thrown if property construction fails */ public DeploymentConfiguration createPropertyDeploymentConfiguration( - Class systemPropertyBaseClass, VaadinConfig vaadinConfig) - throws VaadinConfigurationException { + Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { return new PropertyDeploymentConfiguration( ApplicationConfiguration.get(vaadinConfig.getVaadinContext()), systemPropertyBaseClass, @@ -103,7 +101,7 @@ public DeploymentConfiguration createPropertyDeploymentConfiguration( * thrown if property construction fails */ protected Properties createInitParameters(Class systemPropertyBaseClass, - VaadinConfig vaadinConfig) throws VaadinConfigurationException { + VaadinConfig vaadinConfig) { Properties initParameters = new Properties(); readUiFromEnclosingClass(systemPropertyBaseClass, initParameters); @@ -115,13 +113,12 @@ protected Properties createInitParameters(Class systemPropertyBaseClass, vaadinConfig.getConfigParameter(name)); } - readBuildInfo(systemPropertyBaseClass, initParameters, - vaadinConfig.getVaadinContext()); + readBuildInfo(initParameters, vaadinConfig.getVaadinContext()); return initParameters; } - private void readBuildInfo(Class systemPropertyBaseClass, - Properties initParameters, VaadinContext context) { + private void readBuildInfo(Properties initParameters, + VaadinContext context) { String json = getTokenFileContent(initParameters::getProperty); FallbackChunk fallbackChunk = null; diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinConfigurationException.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinConfigurationException.java deleted file mode 100644 index 8e07e0df614..00000000000 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinConfigurationException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2020 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.flow.server; - -/** - * Exception thrown for failures in the generation of a deployment configuration - * object. - */ -public class VaadinConfigurationException extends Exception { - - /** - * Exception constructor. - * - * @param message - * exception message - * @param exception - * exception cause - */ - public VaadinConfigurationException(String message, Exception exception) { - super(message, exception); - } -} diff --git a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java index a1c4bfe82a4..c481473cf59 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/VaadinServlet.java @@ -181,15 +181,10 @@ public static VaadinServlet getCurrent() { */ protected DeploymentConfiguration createDeploymentConfiguration() throws ServletException { - try { - return createDeploymentConfiguration( - new DeploymentConfigurationFactory().createInitParameters( - getClass(), - new VaadinServletConfig(getServletConfig()))); - } catch (VaadinConfigurationException e) { - throw new ServletException( - "Failed to construct DeploymentConfiguration.", e); - } + return createDeploymentConfiguration( + new DeploymentConfigurationFactory().createInitParameters( + getClass(), + new VaadinServletConfig(getServletConfig()))); } /** diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java index 93f1c7dc326..d8d2e87b7fd 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/ServletDeployer.java @@ -37,7 +37,6 @@ import com.vaadin.flow.server.DeploymentConfigurationFactory; import com.vaadin.flow.server.InitParameters; import com.vaadin.flow.server.VaadinConfig; -import com.vaadin.flow.server.VaadinConfigurationException; import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.VaadinService; import com.vaadin.flow.server.VaadinServlet; @@ -179,17 +178,11 @@ public Enumeration getInitParameterNames() { public static DeploymentConfiguration createDeploymentConfiguration( ServletContext context, ServletRegistration registration, Class servletClass) { - try { - ServletConfig servletConfig = new StubServletConfig(context, - registration); - return new DeploymentConfigurationFactory() - .createPropertyDeploymentConfiguration(servletClass, - new VaadinServletConfig(servletConfig)); - } catch (VaadinConfigurationException e) { - throw new IllegalStateException(String.format( - "Failed to get deployment configuration data for servlet with name '%s' and class '%s'", - registration.getName(), servletClass), e); - } + ServletConfig servletConfig = new StubServletConfig(context, + registration); + return new DeploymentConfigurationFactory() + .createPropertyDeploymentConfiguration(servletClass, + new VaadinServletConfig(servletConfig)); } /** @@ -203,15 +196,9 @@ public static DeploymentConfiguration createDeploymentConfiguration( */ public static DeploymentConfiguration createDeploymentConfiguration( ServletContext context, Class servletClass) { - try { - return new DeploymentConfigurationFactory() - .createPropertyDeploymentConfiguration(servletClass, - new VaadinServletContextConfig(context)); - } catch (VaadinConfigurationException e) { - throw new IllegalStateException(String.format( - "Failed to get deployment configuration data for servlet class '%s'", - servletClass), e); - } + return new DeploymentConfigurationFactory() + .createPropertyDeploymentConfiguration(servletClass, + new VaadinServletContextConfig(context)); } } diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 89854939775..5a21a5d6645 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -79,8 +79,7 @@ private static class TestDeploymentConfigurationFactory extends DeploymentConfigurationFactory { @Override protected Properties createInitParameters( - Class systemPropertyBaseClass, VaadinConfig vaadinConfig) - throws VaadinConfigurationException { + Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { return super.createInitParameters(systemPropertyBaseClass, vaadinConfig); } @@ -348,7 +347,7 @@ public void externalStatsFileTrue_predefinedValuesAreNotOverridden() @Test public void createInitParameters_fallbackChunkIsCreatedViaAppConfig_fallbackChunkObjectIsInInitParams() - throws VaadinConfigurationException, IOException { + throws IOException { ServletContext context = Mockito.mock(ServletContext.class); ServletConfig config = Mockito.mock(ServletConfig.class); ApplicationConfiguration appConfig = Mockito @@ -375,7 +374,7 @@ public void createInitParameters_fallbackChunkIsCreatedViaAppConfig_fallbackChun @Test public void createInitParameters_servletConfigDefinesTokenFile_fallbackChunkObjectIsInInitParams() - throws IOException, VaadinConfigurationException { + throws IOException { ServletContext context = Mockito.mock(ServletContext.class); ServletConfig config = Mockito.mock(ServletConfig.class); Mockito.when(config.getServletContext()).thenReturn(context); diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java index abc462639fe..f7e09af38cc 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java @@ -34,7 +34,6 @@ import com.vaadin.flow.di.Lookup; import com.vaadin.flow.di.ResourceProvider; import com.vaadin.flow.server.VaadinConfig; -import com.vaadin.flow.server.VaadinConfigurationException; import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -49,7 +48,7 @@ public class DefaultApplicationConfigurationFactoryTest { @Test public void getTokenFileFromClassloader_tokenFileIsRead_checkWebpackGeneratedFromContext() - throws VaadinConfigurationException, IOException { + throws IOException { VaadinContext context = Mockito.mock(VaadinContext.class); VaadinConfig config = Mockito.mock(VaadinConfig.class); @@ -105,8 +104,7 @@ public void create_tokenFileIsSetViaContext_tokenFileIsReadViaContextProperty_pr } @Test - public void create_propertiesAreReadFromContext() - throws IOException, VaadinConfigurationException { + public void create_propertiesAreReadFromContext() throws IOException { VaadinContext context = Mockito.mock(VaadinContext.class); VaadinConfig config = Mockito.mock(VaadinConfig.class); ResourceProvider resourceProvider = mockResourceProvider(config, @@ -150,7 +148,7 @@ protected URLConnection openConnection(URL u) throws IOException { } private ResourceProvider mockResourceProvider(VaadinConfig config, - VaadinContext context) throws VaadinConfigurationException { + VaadinContext context) { Mockito.when(config.getVaadinContext()).thenReturn(context); Mockito.when(context.getContextParameterNames()) From 1b4e4bbe1ecb42bae248f7b8c0c67e32e06d8ce6 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Sat, 19 Dec 2020 18:44:58 +0300 Subject: [PATCH 30/32] fix: review comments --- .../startup/AbstractConfigurationFactory.java | 10 +++ .../communication/UidlRequestHandlerTest.java | 71 +++++++++++++------ 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java index 7da7e285043..19a63cc3ecc 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/startup/AbstractConfigurationFactory.java @@ -157,6 +157,16 @@ protected Map getConfigParametersUsingTokenData( return params; } + /** + * Sets to the dev mode properties to the configuration parameters. + * + * @see #getConfigParametersUsingTokenData(JsonObject) + * + * @param params + * the configuration parameters to set dev mode properties to + * @param buildInfo + * the token file data + */ protected void setDevModePropertiesUsingTokenData( Map params, JsonObject buildInfo) { // read dev mode properties from the token and set init parameter only diff --git a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java index 15ddc12dc7c..84a5af76ade 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/communication/UidlRequestHandlerTest.java @@ -232,29 +232,54 @@ public void should_not_modify_non_MPR_Uidl() throws Exception { } private JsonObject generateUidl(boolean withLocation, boolean withHash) { - JsonObject uidl = JsonUtil.parse("{" + " \"syncId\": 3," - + " \"clientId\": 3," + " \"changes\": []," - + " \"execute\": [" + " [\"\", \"document.title = $0\"]," - + " [\"\", \"setTimeout(() => window.history.pushState(null, '', $0))\"]," - + " [[0, 16], \"___PLACE_FOR_V7_UIDL___\", \"$0.firstElementChild.setResponse($1)\"]," - + " [1,null,[0, 16], \"return (function() { this.$server['}p']($0, true, $1)}).apply($2)\"]" - + " ]," + " \"timings\": []" + "}"); - - String v7String = "\"syncId\": 2," + "\"clientId\": 2," - + "\"changes\": [" - + " [],[\"___PLACE_FOR_LOCATION_CHANGE___\"]" + "]," - + "\"state\": {" + "}," + "\"types\": {" + "}," - + "\"hierarchy\": {" + "}," + "\"rpc\": [" + " [],[" - + " \"11\"," - + " \"com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc\"," - + " \"executeJavaScript\", [ \"___PLACE_FOR_HASH_RPC___\" ]" - + " ],[" + " \"12\"," + " \"com.example.FooRpc\"," - + " \"barMethod\", [{}, {}]" + " ],[]" + "]," - + "\"meta\": {}, \"resources\": {},\"typeMappings\": {},\"typeInheritanceMap\": {}, \"timings\": []"; - - String locationChange = "\"change\", {\"pid\": \"0\"}, [\"0\", {\"id\": \"0\", \"location\": \"http://localhost:9998/#!away\"}]"; - - String hashRpc = "window.location.hash = '!away';"; + + // @formatter:off + JsonObject uidl = JsonUtil.parse( + "{" + + " \"syncId\": 3," + + " \"clientId\": 3," + + " \"changes\": []," + + " \"execute\": [" + + " [\"\", \"document.title = $0\"]," + + " [\"\", \"setTimeout(() => window.history.pushState(null, '', $0))\"]," + + " [[0, 16], \"___PLACE_FOR_V7_UIDL___\", \"$0.firstElementChild.setResponse($1)\"]," + + " [1,null,[0, 16], \"return (function() { this.$server['}p']($0, true, $1)}).apply($2)\"]" + + " ]," + + " \"timings\": []" + + "}"); + + String v7String = + "\"syncId\": 2," + + "\"clientId\": 2," + + "\"changes\": [" + + " [],[\"___PLACE_FOR_LOCATION_CHANGE___\"]" + + "]," + + "\"state\": {" + + "}," + + "\"types\": {" + + "}," + + "\"hierarchy\": {" + + "}," + + "\"rpc\": [" + + " [],[" + + " \"11\"," + + " \"com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc\"," + + " \"executeJavaScript\", [ \"___PLACE_FOR_HASH_RPC___\" ]" + + " ],[" + + " \"12\"," + + " \"com.example.FooRpc\"," + + " \"barMethod\", [{}, {}]" + + " ],[]" + + "]," + + "\"meta\": {}, \"resources\": {},\"typeMappings\": {},\"typeInheritanceMap\": {}, \"timings\": []"; + + String locationChange = + "\"change\", {\"pid\": \"0\"}, [\"0\", {\"id\": \"0\", \"location\": \"http://localhost:9998/#!away\"}]"; + + String hashRpc = + "window.location.hash = '!away';"; + + // @formatter:on if (withLocation) { v7String = v7String.replace("\"___PLACE_FOR_LOCATION_CHANGE___\"", From c72c9726852c515bc2746317990de0dca59cd763 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 21 Dec 2020 09:56:38 +0300 Subject: [PATCH 31/32] test: extend unit test with checking token file reading --- .../DeploymentConfigurationFactory.java | 6 - .../DeploymentConfigurationFactoryTest.java | 96 ++++++++++++-- ...ltApplicationConfigurationFactoryTest.java | 120 ++++++++++++++++-- 3 files changed, 193 insertions(+), 29 deletions(-) diff --git a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java index 4a414799798..1b9395961a2 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/DeploymentConfigurationFactory.java @@ -56,8 +56,6 @@ public class DeploymentConfigurationFactory extends AbstractConfigurationFactory * @param vaadinConfig * the config to get the rest of the properties from * @return {@link DeploymentConfiguration} instance - * @throws VaadinConfigurationException - * thrown if property construction fails */ public DeploymentConfiguration createDeploymentConfiguration( Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { @@ -77,8 +75,6 @@ public DeploymentConfiguration createDeploymentConfiguration( * @param vaadinConfig * the config to get the rest of the properties from * @return {@link DeploymentConfiguration} instance - * @throws VaadinConfigurationException - * thrown if property construction fails */ public DeploymentConfiguration createPropertyDeploymentConfiguration( Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { @@ -97,8 +93,6 @@ public DeploymentConfiguration createPropertyDeploymentConfiguration( * @param vaadinConfig * the config to get the rest of the properties from * @return {@link Properties} instance - * @throws VaadinConfigurationException - * thrown if property construction fails */ protected Properties createInitParameters(Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java index 5a21a5d6645..f4f15d733d7 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/DeploymentConfigurationFactoryTest.java @@ -75,16 +75,6 @@ private static class ServletWithEnclosingUi extends VaadinServlet { } } - private static class TestDeploymentConfigurationFactory - extends DeploymentConfigurationFactory { - @Override - protected Properties createInitParameters( - Class systemPropertyBaseClass, VaadinConfig vaadinConfig) { - return super.createInitParameters(systemPropertyBaseClass, - vaadinConfig); - } - } - @Before public void setup() throws IOException { System.setProperty("user.dir", @@ -293,7 +283,7 @@ public void shouldNotThrow_tokenFileFoldersExist() throws Exception { @Test public void createInitParameters_valuesFromContextAreIgnored_valuesAreTakenFromservletConfig() throws Exception { - TestDeploymentConfigurationFactory factory = new TestDeploymentConfigurationFactory(); + DeploymentConfigurationFactory factory = new DeploymentConfigurationFactory(); VaadinContext context = Mockito.mock(VaadinContext.class); VaadinConfig config = Mockito.mock(VaadinConfig.class); @@ -322,6 +312,90 @@ public void createInitParameters_valuesFromContextAreIgnored_valuesAreTakenFroms Assert.assertFalse(parameters.contains("bar")); } + @Test + public void createInitParameters_tokenFileIsSetViaContext_externalStatsUrlIsReadFromTokenFile_predefinedProperties() + throws Exception { + DeploymentConfigurationFactory factory = new DeploymentConfigurationFactory(); + + VaadinConfig config = mockTokenFileViaContextParam( + "{ 'externalStatsUrl': 'http://my.server/static/stats.json'}"); + + Properties parameters = factory.createInitParameters(Object.class, + config); + + Assert.assertEquals("http://my.server/static/stats.json", + parameters.get(Constants.EXTERNAL_STATS_URL)); + Assert.assertEquals(Boolean.TRUE.toString(), + parameters.get(Constants.EXTERNAL_STATS_FILE)); + Assert.assertEquals(Boolean.FALSE.toString(), parameters + .get(InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER)); + } + + @Test + public void createInitParameters_tokenFileIsSetViaContext_externalStatsFileIsReadFromTokenFile_predefinedProperties() + throws Exception { + DeploymentConfigurationFactory factory = new DeploymentConfigurationFactory(); + + VaadinConfig config = mockTokenFileViaContextParam( + "{ 'externalStatsFile': true}"); + + Properties parameters = factory.createInitParameters(Object.class, + config); + + Assert.assertEquals(Boolean.TRUE.toString(), + parameters.get(Constants.EXTERNAL_STATS_FILE)); + Assert.assertEquals(Boolean.FALSE.toString(), parameters + .get(InitParameters.SERVLET_PARAMETER_ENABLE_DEV_SERVER)); + } + + @Test + public void createInitParameters_tokenFileIsSetViaContext_setPropertyFromTokenFile() + throws Exception { + DeploymentConfigurationFactory factory = new DeploymentConfigurationFactory(); + + VaadinConfig config = mockTokenFileViaContextParam( + "{ '" + SERVLET_PARAMETER_PRODUCTION_MODE + "': true}"); + + Properties parameters = factory.createInitParameters(Object.class, + config); + + Assert.assertEquals(Boolean.TRUE.toString(), + parameters.get(SERVLET_PARAMETER_PRODUCTION_MODE)); + } + + private VaadinConfig mockTokenFileViaContextParam(String content) + throws IOException { + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); + + ApplicationConfiguration appConfig = Mockito + .mock(ApplicationConfiguration.class); + + Mockito.when(config.getConfigParameterNames()) + .thenReturn(Collections.enumeration( + Collections.singleton(FrontendUtils.PARAM_TOKEN_FILE))); + Mockito.when(context.getContextParameterNames()) + .thenReturn(Collections.emptyEnumeration()); + + Mockito.when(config.getVaadinContext()).thenReturn(context); + + File tmpFile = temporaryFolder.newFile(); + Files.write(tmpFile.toPath(), Collections.singletonList(content)); + + Mockito.when( + context.getContextParameter(FrontendUtils.PARAM_TOKEN_FILE)) + .thenReturn(tmpFile.getPath()); + + Mockito.when(config.getConfigParameter(FrontendUtils.PARAM_TOKEN_FILE)) + .thenReturn(tmpFile.toString()); + + Mockito.when(context.getAttribute( + Mockito.eq(ApplicationConfiguration.class), Mockito.any())) + .thenReturn(appConfig); + + return config; + } + @Test public void externalStatsFileTrue_predefinedValuesAreNotOverridden() throws Exception { diff --git a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java index f7e09af38cc..72b385882d3 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/startup/DefaultApplicationConfigurationFactoryTest.java @@ -33,6 +33,7 @@ import com.vaadin.flow.di.Lookup; import com.vaadin.flow.di.ResourceProvider; +import com.vaadin.flow.server.Constants; import com.vaadin.flow.server.VaadinConfig; import com.vaadin.flow.server.VaadinContext; import com.vaadin.flow.server.frontend.FrontendUtils; @@ -73,21 +74,54 @@ public void getTokenFileFromClassloader_tokenFileIsRead_checkWebpackGeneratedFro } @Test - public void create_tokenFileIsSetViaContext_tokenFileIsReadViaContextProperty_propertiesAreReadFromContext() - throws IOException { + public void create_tokenFileIsReadFromClassloader_externalStatsFileIsReadFromTokenFile_predefinedContext() + throws MalformedURLException, IOException { VaadinContext context = Mockito.mock(VaadinContext.class); - Mockito.when(context.getContextParameterNames()) - .thenReturn(Collections.enumeration( - Collections.singleton(FrontendUtils.PARAM_TOKEN_FILE))); + VaadinConfig config = Mockito.mock(VaadinConfig.class); - File tmpFile = temporaryFolder.newFile(); - String content = "{ '" + SERVLET_PARAMETER_USE_V14_BOOTSTRAP - + "':true }"; - Files.write(tmpFile.toPath(), Collections.singletonList(content)); + ResourceProvider resourceProvider = mockResourceProvider(config, + context); - Mockito.when( - context.getContextParameter(FrontendUtils.PARAM_TOKEN_FILE)) - .thenReturn(tmpFile.getPath()); + String content = "{ 'externalStatsFile':true }"; + mockClassPathTokenFile(resourceProvider, content); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertTrue( + propertyNames.contains(Constants.EXTERNAL_STATS_FILE)); + Assert.assertTrue(configuration + .getBooleanProperty(Constants.EXTERNAL_STATS_FILE, false)); + Assert.assertFalse(configuration.isProductionMode()); + Assert.assertFalse(configuration.enableDevServer()); + } + + @Test + public void create_tokenFileIsSetViaContext_externalStatsFileIsReadFromTokenFile_predefinedContext() + throws MalformedURLException, IOException { + String content = "{ 'externalStatsFile':true }"; + VaadinContext context = mockTokenFileViaContextParam(content); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertTrue( + propertyNames.contains(Constants.EXTERNAL_STATS_FILE)); + Assert.assertTrue(configuration + .getBooleanProperty(Constants.EXTERNAL_STATS_FILE, false)); + Assert.assertFalse(configuration.isProductionMode()); + Assert.assertFalse(configuration.enableDevServer()); + } + + @Test + public void create_tokenFileIsSetViaContext_tokenFileIsReadViaContextProperty_propertiesAreReadFromContext() + throws IOException { + VaadinContext context = mockTokenFileViaContextParam( + "{ '" + SERVLET_PARAMETER_USE_V14_BOOTSTRAP + "':true }"); DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); ApplicationConfiguration configuration = factory.create(context); @@ -103,6 +137,52 @@ public void create_tokenFileIsSetViaContext_tokenFileIsReadViaContextProperty_pr Assert.assertTrue(configuration.useV14Bootstrap()); } + @Test + public void create_tokenFileIsSetViaContext_externalStatsUrlIsReadFromTokenFile_predefinedContext() + throws MalformedURLException, IOException { + String content = "{ 'externalStatsUrl': 'http://my.server/static/stats.json'}"; + VaadinContext context = mockTokenFileViaContextParam(content); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertTrue(propertyNames.contains(Constants.EXTERNAL_STATS_URL)); + Assert.assertTrue(configuration + .getBooleanProperty(Constants.EXTERNAL_STATS_FILE, false)); + Assert.assertEquals("http://my.server/static/stats.json", configuration + .getStringProperty(Constants.EXTERNAL_STATS_URL, null)); + Assert.assertFalse(configuration.isProductionMode()); + Assert.assertFalse(configuration.enableDevServer()); + } + + @Test + public void create_tokenFileIsReadFromClassloader_externalStatsUrlIsReadFromTokenFile_predefinedContext() + throws IOException { + VaadinContext context = Mockito.mock(VaadinContext.class); + VaadinConfig config = Mockito.mock(VaadinConfig.class); + + ResourceProvider resourceProvider = mockResourceProvider(config, + context); + + mockClassPathTokenFile(resourceProvider, + "{ 'externalStatsUrl': 'http://my.server/static/stats.json'}"); + + DefaultApplicationConfigurationFactory factory = new DefaultApplicationConfigurationFactory(); + ApplicationConfiguration configuration = factory.create(context); + + List propertyNames = Collections + .list(configuration.getPropertyNames()); + Assert.assertTrue(propertyNames.contains(Constants.EXTERNAL_STATS_URL)); + Assert.assertTrue(configuration + .getBooleanProperty(Constants.EXTERNAL_STATS_FILE, false)); + Assert.assertEquals("http://my.server/static/stats.json", configuration + .getStringProperty(Constants.EXTERNAL_STATS_URL, null)); + Assert.assertFalse(configuration.isProductionMode()); + Assert.assertFalse(configuration.enableDevServer()); + } + @Test public void create_propertiesAreReadFromContext() throws IOException { VaadinContext context = Mockito.mock(VaadinContext.class); @@ -174,4 +254,20 @@ private ResourceProvider mockResourceProvider(VaadinConfig config, return resourceProvider; } + + private VaadinContext mockTokenFileViaContextParam(String content) + throws IOException { + VaadinContext context = Mockito.mock(VaadinContext.class); + Mockito.when(context.getContextParameterNames()) + .thenReturn(Collections.enumeration( + Collections.singleton(FrontendUtils.PARAM_TOKEN_FILE))); + + File tmpFile = temporaryFolder.newFile(); + Files.write(tmpFile.toPath(), Collections.singletonList(content)); + + Mockito.when( + context.getContextParameter(FrontendUtils.PARAM_TOKEN_FILE)) + .thenReturn(tmpFile.getPath()); + return context; + } } From 0d98d6de6372af550bcc18a2e2b331f2e5545634 Mon Sep 17 00:00:00 2001 From: Denis Anisimov Date: Mon, 21 Dec 2020 12:26:43 +0300 Subject: [PATCH 32/32] test: add a test to check that every method has its own impl --- .../PropertyDeploymentConfigurationTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java index 64e33551579..c303828adb5 100644 --- a/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java +++ b/flow-server/src/test/java/com/vaadin/flow/server/PropertyDeploymentConfigurationTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.flow.server; +import java.lang.reflect.Method; import java.util.Collections; import java.util.Properties; @@ -396,6 +397,27 @@ public void getInitParameters_prorprtiesAreMergedFromParentAndDeploymentConfig() Assert.assertEquals("baz", initParameters.get("bar")); } + @Test + public void allDefaultAbstractConfigurationMethodsAreOverridden() { + Method[] methods = PropertyDeploymentConfiguration.class.getMethods(); + for (Method method : methods) { + Assert.assertNotEquals("There is a method '" + method.getName() + + "' which is declared in " + AbstractConfiguration.class + + " interface but it's not overriden in the " + + PropertyDeploymentConfiguration.class + + ". That's most likely a mistake because every method implementation in " + + PropertyDeploymentConfiguration.class + + " must take into account parent " + + ApplicationConfiguration.class + + " API which shares the same interface " + + AbstractConfiguration.class + " with " + + PropertyDeploymentConfiguration.class + + ", so every API method should call parent config and may not use just default implementation of " + + AbstractConfiguration.class, AbstractConfiguration.class, + method.getDeclaringClass()); + } + } + private ApplicationConfiguration mockAppConfig() { ApplicationConfiguration appConfig = Mockito .mock(ApplicationConfiguration.class);