Package org.springframework.boot.test

Source Code of org.springframework.boot.test.SpringApplicationContextLoader$WebConfigurer

/*
* Copyright 2012-2014 the original author or authors.
*
* 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 org.springframework.boot.test;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.web.ServletContextApplicationContextInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.SpringVersion;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextLoader;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.support.AbstractContextLoader;
import org.springframework.test.context.support.AnnotationConfigContextLoaderUtils;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.context.web.WebMergedContextConfiguration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.GenericWebApplicationContext;

/**
* A {@link ContextLoader} that can be used to test Spring Boot applications (those that
* normally startup using {@link SpringApplication}). Normally never starts an embedded
* web server, but detects the {@link WebAppConfiguration @WebAppConfiguration} annotation
* on the test class and only creates a web application context if it is present. Non-web
* features, like a repository layer, can be tested cleanly by simply <em>not</em> marking
* the test class <code>@WebAppConfiguration</code>.
* <p>
* If you <em>want</em> to start a web server, mark the test class as
* <code>@WebAppConfiguration @IntegrationTest</code>. This is useful for testing HTTP
* endpoints using {@link TestRestTemplate} (for instance), especially since you can
* <code>@Autowired</code> application context components into your test case to see the
* internal effects of HTTP requests directly.
* <p>
* If <code>@ActiveProfiles</code> are provided in the test class they will be used to
* create the application context.
*
* @author Dave Syer
* @see IntegrationTest
*/
public class SpringApplicationContextLoader extends AbstractContextLoader {

  private static final String LINE_SEPARATOR = System.getProperty("line.separator");

  @Override
  public ApplicationContext loadContext(MergedContextConfiguration config)
      throws Exception {
    SpringApplication application = getSpringApplication();
    application.setSources(getSources(config));
    ConfigurableEnvironment environment = new StandardEnvironment();
    if (!ObjectUtils.isEmpty(config.getActiveProfiles())) {
      String profiles = StringUtils.arrayToCommaDelimitedString(config
          .getActiveProfiles());
      EnvironmentTestUtils.addEnvironment(environment, "spring.profiles.active="
          + profiles);
    }
    // Ensure @IntegrationTest properties go before external config and after system
    environment.getPropertySources()
        .addAfter(
            StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
            new MapPropertySource("integrationTest",
                getEnvironmentProperties(config)));
    application.setEnvironment(environment);
    List<ApplicationContextInitializer<?>> initializers = getInitializers(config,
        application);
    if (config instanceof WebMergedContextConfiguration) {
      new WebConfigurer().configure(config, application, initializers);
    }
    else {
      application.setWebEnvironment(false);
    }
    application.setInitializers(initializers);
    return application.run();
  }

  @Override
  public void processContextConfiguration(
      ContextConfigurationAttributes configAttributes) {
    if (!configAttributes.hasLocations() && !configAttributes.hasClasses()) {
      Class<?>[] defaultConfigClasses = detectDefaultConfigurationClasses(configAttributes
          .getDeclaringClass());
      configAttributes.setClasses(defaultConfigClasses);
    }
  }

  /**
   * Builds new {@link org.springframework.boot.SpringApplication} instance. You can
   * override this method to add custom behaviour
   * @return {@link org.springframework.boot.SpringApplication} instance
   */
  protected SpringApplication getSpringApplication() {
    return new SpringApplication();
  }

  private Set<Object> getSources(MergedContextConfiguration mergedConfig) {
    Set<Object> sources = new LinkedHashSet<Object>();
    sources.addAll(Arrays.asList(mergedConfig.getClasses()));
    sources.addAll(Arrays.asList(mergedConfig.getLocations()));
    if (sources.isEmpty()) {
      throw new IllegalStateException(
          "No configuration classes or locations found in @SpringApplicationConfiguration. "
              + "For default configuration detection to work you need Spring 4.0.3 or better (found "
              + SpringVersion.getVersion() + ").");
    }
    return sources;
  }

  /**
   * Detect the default configuration classes for the supplied test class. By default
   * simply delegates to
   * {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses} .
   * @param declaringClass the test class that declared {@code @ContextConfiguration}
   * @return an array of default configuration classes, potentially empty but never
   * {@code null}
   * @see AnnotationConfigContextLoaderUtils
   */
  protected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
    return AnnotationConfigContextLoaderUtils
        .detectDefaultConfigurationClasses(declaringClass);
  }

  protected Map<String, Object> getEnvironmentProperties(
      MergedContextConfiguration config) {
    Map<String, Object> properties = new LinkedHashMap<String, Object>();
    // JMX bean names will clash if the same bean is used in multiple contexts
    disableJmx(properties);
    properties.putAll(extractEnvironmentProperties(config
        .getPropertySourceProperties()));
    if (AnnotationUtils.findAnnotation(config.getTestClass(), IntegrationTest.class) == null) {
      properties.putAll(getDefaultEnvironmentProperties());
    }
    return properties;
  }

  private void disableJmx(Map<String, Object> properties) {
    properties.put("spring.jmx.enabled", "false");
  }

  private Map<String, String> getDefaultEnvironmentProperties() {
    return Collections.singletonMap("server.port", "-1");
  }

  Map<String, Object> extractEnvironmentProperties(String[] values) {
    // Instead of parsing the keys ourselves, we rely on standard handling
    if (values == null) {
      return Collections.emptyMap();
    }
    String content = StringUtils.arrayToDelimitedString(values, LINE_SEPARATOR);
    Properties properties = new Properties();
    try {
      properties.load(new StringReader(content));
      return asMap(properties);
    }
    catch (IOException ex) {
      throw new IllegalStateException("Unexpected could not load properties from '"
          + content + "'", ex);
    }
  }

  private Map<String, Object> asMap(Properties properties) {
    Map<String, Object> map = new LinkedHashMap<String, Object>();
    for (String name : properties.stringPropertyNames()) {
      map.put(name, properties.getProperty(name));
    }
    return map;
  }

  private List<ApplicationContextInitializer<?>> getInitializers(
      MergedContextConfiguration mergedConfig, SpringApplication application) {
    List<ApplicationContextInitializer<?>> initializers = new ArrayList<ApplicationContextInitializer<?>>();
    initializers.add(new ServerPortInfoApplicationContextInitializer());
    initializers.addAll(application.getInitializers());
    for (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig
        .getContextInitializerClasses()) {
      initializers.add(BeanUtils.instantiate(initializerClass));
    }
    return initializers;
  }

  @Override
  public ApplicationContext loadContext(String... locations) throws Exception {
    throw new UnsupportedOperationException(
        "SpringApplicationContextLoader does not support the loadContext(String...) method");
  }

  @Override
  protected String getResourceSuffix() {
    return "-context.xml";
  }

  private static class WebConfigurer {

    void configure(MergedContextConfiguration configuration,
        SpringApplication application,
        List<ApplicationContextInitializer<?>> initializers) {
      WebMergedContextConfiguration webConfiguration = (WebMergedContextConfiguration) configuration;
      if (AnnotationUtils.findAnnotation(webConfiguration.getTestClass(),
          IntegrationTest.class) == null) {
        MockServletContext servletContext = new MockServletContext(
            webConfiguration.getResourceBasePath());
        initializers.add(0, new ServletContextApplicationContextInitializer(
            servletContext));
        application
            .setApplicationContextClass(GenericWebApplicationContext.class);
      }
    }

  }

}
TOP

Related Classes of org.springframework.boot.test.SpringApplicationContextLoader$WebConfigurer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.