/*
* Copyright 2016 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.togglz.spring.boot.autoconfigure;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.togglz.core.Feature;
import org.togglz.core.activation.Parameter;
import org.togglz.core.context.FeatureContext;
import org.togglz.core.manager.EmptyFeatureProvider;
import org.togglz.core.manager.EnumBasedFeatureProvider;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.repository.FeatureState;
import org.togglz.core.repository.StateRepository;
import org.togglz.core.repository.cache.CachingStateRepository;
import org.togglz.core.repository.file.FileBasedStateRepository;
import org.togglz.core.repository.mem.InMemoryStateRepository;
import org.togglz.core.repository.property.PropertyBasedStateRepository;
import org.togglz.core.spi.ActivationStrategy;
import org.togglz.core.spi.FeatureProvider;
import org.togglz.core.user.FeatureUser;
import org.togglz.core.user.UserProvider;
import org.togglz.spring.util.ContextClassLoaderApplicationContextHolder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.*;
/**
* Tests for {@link TogglzAutoConfiguration}.
*
* @author Marcel Overdijk
*/
public class TogglzAutoConfigurationTest {
private AnnotationConfigWebApplicationContext context;
@After
public void tearDown() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void defaultTogglz() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class});
FeatureManager featureManager = this.context.getBean(FeatureManager.class);
Set<Feature> features = featureManager.getFeatures();
assertNotNull(featureManager);
assertSame(featureManager, FeatureContext.getFeatureManager());
assertSame(this.context, ContextClassLoaderApplicationContextHolder.get());
assertEquals(2, features.size());
assertTrue(features.contains(MyFeatures.FEATURE_ONE));
assertTrue(features.contains(MyFeatures.FEATURE_TWO));
assertTrue(this.context.getBean(StateRepository.class) instanceof InMemoryStateRepository);
assertEquals(1, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertTrue(this.context.getBean(ServletRegistrationBean.class).getUrlMappings().contains("/togglz-console/*"));
TogglzEndpoint togglzEndpoint = this.context.getBean(TogglzEndpoint.class);
assertEquals("togglz", togglzEndpoint.getId());
assertTrue(togglzEndpoint.isEnabled());
assertTrue(togglzEndpoint.isSensitive());
}
@Test
public void applicationContextBinder() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class});
assertSame(this.context, ContextClassLoaderApplicationContextHolder.get());
}
@Test
public void disabled() {
// Explicitly clear cache
FeatureContext.clearCache();
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.enabled: false");
assertNull(FeatureContext.getFeatureManagerOrNull());
assertNull(ContextClassLoaderApplicationContextHolder.get());
assertEquals(0, this.context.getBeansOfType(FeatureManager.class).size());
assertEquals(0, this.context.getBeansOfType(ActivationStrategy.class).size());
assertEquals(0, this.context.getBeansOfType(StateRepository.class).size());
assertEquals(0, this.context.getBeansOfType(UserProvider.class).size());
assertEquals(0, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertEquals(0, this.context.getBeansOfType(TogglzEndpoint.class).size());
}
@Test
public void noFeatureProviderBeanAndFeatureEnumsProperty() {
loadWithDefaults();
assertTrue(this.context.getBean(FeatureProvider.class) instanceof EmptyFeatureProvider);
}
@Test
public void featureEnums() {
loadWithDefaults("togglz.feature-enums: org.togglz.spring.boot.autoconfigure.TogglzAutoConfigurationTest.MyFeatures");
FeatureManager featureManager = this.context.getBean(FeatureManager.class);
Set<Feature> features = featureManager.getFeatures();
assertNotNull(featureManager);
assertEquals(2, features.size());
assertTrue(features.contains(MyFeatures.FEATURE_ONE));
assertTrue(features.contains(MyFeatures.FEATURE_TWO));
}
@Test(expected = BeanCreationException.class)
public void featureEnumsClassNotFound() {
loadWithDefaults("togglz.feature-enums: i.dont.exist.features");
}
@Test
public void customFeatureManagerName() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.feature-manager-name: Custom Feature Manager Name");
assertEquals("Custom Feature Manager Name", this.context.getBean(FeatureManager.class).getName());
}
@Test
public void features() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.features.FEATURE_ONE: true",
"togglz.features.FEATURE_TWO: false");
FeatureManager featureManager = this.context.getBean(FeatureManager.class);
assertTrue(featureManager.isActive(MyFeatures.FEATURE_ONE));
assertFalse(featureManager.isActive(MyFeatures.FEATURE_TWO));
assertTrue(this.context.getBean(StateRepository.class) instanceof PropertyBasedStateRepository);
}
@Test
public void featuresFile() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.features-file: classpath:/features-file/features.properties");
FeatureManager featureManager = this.context.getBean(FeatureManager.class);
assertTrue(featureManager.isActive(MyFeatures.FEATURE_ONE));
assertFalse(featureManager.isActive(MyFeatures.FEATURE_TWO));
assertTrue(this.context.getBean(StateRepository.class) instanceof FileBasedStateRepository);
}
@Test
public void cacheEnabled() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.cache.enabled: true");
assertTrue(this.context.getBean(StateRepository.class) instanceof CachingStateRepository);
}
@Test
public void consoleDisabled() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.console.enabled: false");
assertEquals(0, this.context.getBeansOfType(ServletRegistrationBean.class).size());
}
@Test
public void consoleWithCustomManagementContextPath() {
// With TogglzManagementContextConfiguration responsible for creating the admin console servlet registration bean,
// if a custom managememnt context path is provided it should be used as prefix.
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"management.context-path: /manage");
assertEquals(1, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertTrue(this.context.getBean(ServletRegistrationBean.class).getUrlMappings().contains("/manage/togglz-console/*"));
}
@Test
public void consoleUseManagementPortIsFalseWithoutTogglzManagementContextConfiguration() {
// With togglz.console.use-management-port: false the TogglzAutoConfiguration is responsible for creating the admin console servlet
// registration bean.
// We explicitly do not load the TogglzManagementContextConfiguration to test the registration bean is created by the
// TogglzAutoConfiguration, hence asserting on 1 bean.
load(new Class[]{ManagementServerPropertiesAutoConfiguration.class, FeatureProviderConfig.class, TogglzAutoConfiguration.class},
"togglz.console.use-management-port: false");
assertEquals(1, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertTrue(this.context.getBean(ServletRegistrationBean.class).getUrlMappings().contains("/togglz-console/*"));
}
@Test
public void consoleUseManagementPortIsTrueWithoutTogglzManagementContextConfiguration() {
// With togglz.console.use-management-port: true the TogglzManagementContextConfiguration is responsible for creating the admin
// console servlet registration bean.
// We explicitly do not load the TogglzManagementContextConfiguration to test the registration bean is not added to the context,
// hence asserting on 0 beans.
load(new Class[]{ManagementServerPropertiesAutoConfiguration.class, FeatureProviderConfig.class, TogglzAutoConfiguration.class},
"togglz.console.use-management-port: true");
assertEquals(0, this.context.getBeansOfType(ServletRegistrationBean.class).size());
}
@Test
public void customConsolePath() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.console.path: /custom");
assertEquals(1, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertTrue(this.context.getBean(ServletRegistrationBean.class).getUrlMappings().contains("/custom/*"));
}
@Test
public void customConsolePathWithTrailingSlash() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.console.path: /custom/");
assertEquals(1, this.context.getBeansOfType(ServletRegistrationBean.class).size());
assertTrue(this.context.getBean(ServletRegistrationBean.class).getUrlMappings().contains("/custom/*"));
}
@Test
public void endpointDisabled() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.endpoint.enabled: false");
assertEquals(0, this.context.getBeansOfType(TogglzEndpoint.class).size());
}
@Test
public void endpointNotSensitive() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.endpoint.sensitive: false");
assertFalse(this.context.getBean(TogglzEndpoint.class).isSensitive());
}
@Test
public void customEndpointId() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class},
"togglz.endpoint.id: features");
assertEquals("features", this.context.getBean(TogglzEndpoint.class).getId());
}
@Test
public void customActivationStrategy() {
loadWithDefaults(new Class[]{FeatureProviderConfig.class, ActivationStrategyConfig.class});
FeatureManager featureManager = this.context.getBean(FeatureManager.class);
CustomActivationStrategy customActivationStrategy = this.context.getBean(CustomActivationStrategy.class);
assertTrue(featureManager.getActivationStrategies().contains(customActivationStrategy));
}
private void loadWithDefaults(String... environment) {
loadWithDefaults(new Class[]{}, environment);
}
private void loadWithDefaults(Class<?>[] configs, String... environment) {
List<Class<?>> mergedConfigs = new ArrayList<>();
mergedConfigs.add(ManagementServerPropertiesAutoConfiguration.class);
mergedConfigs.add(TogglzAutoConfiguration.class);
mergedConfigs.add(TogglzManagementContextConfiguration.class);
mergedConfigs.addAll(Arrays.asList(configs));
load(mergedConfigs.toArray(new Class[mergedConfigs.size()]), environment);
}
private void load(Class<?>[] configs, String... environment) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
EnvironmentTestUtils.addEnvironment(this.context, environment);
this.context.refresh();
}
protected enum MyFeatures implements Feature {
FEATURE_ONE,
FEATURE_TWO;
}
protected static class CustomActivationStrategy implements ActivationStrategy {
@Override
public String getId() {
return "custom";
}
@Override
public String getName() {
return "Custom";
}
@Override
public boolean isActive(FeatureState featureState, FeatureUser user) {
return true;
}
@Override
public Parameter[] getParameters() {
return new Parameter[0];
}
}
@Configuration
protected static class FeatureProviderConfig {
@Bean
public FeatureProvider featureProvider() {
return new EnumBasedFeatureProvider(MyFeatures.class);
}
}
@Configuration
protected static class ActivationStrategyConfig {
@Bean
public CustomActivationStrategy customActivationStrategy() {
return new CustomActivationStrategy();
}
}
}