/** * Copyright (C) 2015 Orange * 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.francetelecom.clara.cloud.commons.toggles; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.fest.assertions.Assertions.assertThat; import static com.francetelecom.clara.cloud.commons.toggles.TestLogUtils.*; import java.util.Arrays; import javax.naming.InitialContext; import javax.naming.NameAlreadyBoundException; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import org.junit.Before; import org.junit.Test; import org.togglz.core.Feature; import org.togglz.core.context.FeatureContext; import org.togglz.core.repository.FeatureState; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; public class PaasJndiStateRepositoryTest { private static enum MyFeature implements Feature { FEATURE1, FEATURE2, FEATURE3, FEATURE4; @Override public boolean isActive() { return FeatureContext.getFeatureManager().isActive(this); } } PaasJndiStateRepository repository = spy(new PaasJndiStateRepository()); InitialContext context = mock(InitialContext.class); @Before public void setup() throws Exception { // Stub jndi initial context creation doReturn(context).when(repository).getInitialContext(); } @Test public void getFeatureState_should_fetch_state_from_jndi_when_feature_is_defined_in_jndi() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("false"); when(context.lookup("FEATURE2")).thenReturn("true"); // When FeatureState feature1 = repository.getFeatureState(MyFeature.FEATURE1); FeatureState feature2 = repository.getFeatureState(MyFeature.FEATURE2); // Then assertThat(feature1.isEnabled()).isFalse(); assertThat(feature2.isEnabled()).isTrue(); } @Test public void getFeatureState_should_fetch_users_from_jndi_when_defined_in_jndi() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("true"); when(context.lookup("FEATURE1.users")).thenReturn("user1, user2, user3"); // When FeatureState feature1 = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature1.getUsers()).containsOnly("user1","user2","user3"); } @Test public void getFeatureState_should_return_empty_users_list_when_users_list_is_empty() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("true"); when(context.lookup("FEATURE1.users")).thenReturn(""); // When FeatureState feature1 = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature1.getUsers()).isEmpty(); } @Test public void getFeatureState_should_ignore_spaces_around_comma_in_user_list() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("true"); when(context.lookup("FEATURE1.users")).thenReturn("user1 name , user2 name , user3 name "); // When FeatureState feature1 = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature1.getUsers()).containsOnly("user1 name","user2 name","user3 name"); } @Test public void getFeatureState_should_ignore_last_comma_in_user_list() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("true"); when(context.lookup("FEATURE1.users")).thenReturn("user1, user2, user3,"); // When FeatureState feature1 = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature1.getUsers()).containsOnly("user1","user2","user3"); } @Test public void getFeatureState_should_return_null_when_feature_is_not_defined_in_jndi() throws Exception{ // Given doThrow(new NameNotFoundException("jndi test error")).when(context).lookup(anyString()); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature).isNull(); } @Test public void getFeatureState_should_log_a_warn_when_feature_is_not_defined_in_jndi() throws Exception{ final Appender<ILoggingEvent> mockAppender = addMockAppenderLog(); // Given doThrow(new NameNotFoundException("jndi test error")).when(context).lookup(anyString()); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then verify(mockAppender).doAppend(logEventMatches(Level.WARN, "FEATURE1")); } @Test public void getFeatureState_should_return_null_when_value_is_not_a_string() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn(new Object()); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature).isNull(); } @Test public void getFeatureState_should_return_null_when_value_is_not_true_or_false() throws Exception{ // Given when(context.lookup("FEATURE1")).thenReturn("invalid value"); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature).isNull(); } @Test public void getFeatureState_should_return_null_when_name_not_found_exception_is_wrapped() throws Exception{ final Appender<ILoggingEvent> mockAppender = TestLogUtils.addMockAppenderLog(); // Given doReturn(context).when(repository).getInitialContext(); // stub expected behavior of lookup method NamingException exception = new NamingException("jndi exception"); exception.initCause(new NameNotFoundException("invalid name")); doThrow(exception).when(context).lookup(anyString()); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then assertThat(feature).isNull(); } @Test public void getFeatureState_should_log_a_warn_when_name_not_found_exception_is_wrapped() throws Exception{ final Appender<ILoggingEvent> mockAppender = addMockAppenderLog(); // Given doReturn(context).when(repository).getInitialContext(); // stub expected behavior of lookup method NamingException exception = new NamingException("jndi exception"); exception.initCause(new NameNotFoundException("invalid name")); doThrow(exception).when(context).lookup(anyString()); // When FeatureState feature = repository.getFeatureState(MyFeature.FEATURE1); // Then verify(mockAppender).doAppend(logEventMatches(Level.WARN, "FEATURE1")); } @Test public void setFeatureState_should_add_feature_state_in_jndi_when_not_defined() throws Exception{ // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(context).rebind("FEATURE1", "true"); } @Test public void setFeatureState_should_update_feature_state_in_jndi() throws Exception{ // Given doReturn(context).when(repository).getInitialContext(); // stub expected behavior of bind method doThrow(new NameAlreadyBoundException("jndi error")).when(context).bind(anyString(), anyObject()); // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(context).rebind("FEATURE1", "true"); } @Test public void setFeatureState_should_add_feature_users_in_jndi_when_not_defined() throws Exception{ // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(context).rebind("FEATURE1.users", ""); } @Test public void setFeatureState_should_update_feature_users_in_jndi() throws Exception{ // Given doReturn(context).when(repository).getInitialContext(); // stub expected behavior of bind method doThrow(new NameAlreadyBoundException("jndi error")).when(context).bind(anyString(), anyObject()); // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true, Arrays.asList("user1","user2","user3"))); // Then verify(context).rebind("FEATURE1", "true"); verify(context).rebind("FEATURE1.users", "user1, user2, user3"); } @Test public void setFeatureState_should_silently_ignore_jndi_init_context_errors() throws Exception{ // Given doThrow(new NamingException("jndi error")).when(repository).getInitialContext(); // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(repository).getInitialContext(); } @Test public void setFeatureState_should_silently_ignore_jndi_bind_errors() throws Exception{ // Given doThrow(new NamingException("jndi error")).when(context).bind(anyString(), anyObject()); doThrow(new NamingException("jndi error")).when(context).rebind(anyString(), anyObject()); // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(context).rebind(anyString(),anyObject()); } @Test public void setFeatureState_should_generate_log_error_on_jndi_errors() throws Exception{ final Appender<ILoggingEvent> mockAppender = addMockAppenderLog(); // Given doThrow(new NamingException("jndi error")).when(context).bind(anyString(), anyObject()); doThrow(new NamingException("jndi error")).when(context).rebind(anyString(), anyObject()); // When repository.setFeatureState(new FeatureState(MyFeature.FEATURE1, true)); // Then verify(mockAppender).doAppend(logEventMatches(Level.ERROR, "FEATURE1")); } @Test public void jndi_initial_context_should_be_cached() throws Exception { // Given doCallRealMethod().when(repository).getInitialContext(); doReturn(context).when(repository).createInitialContext(); // When InitialContext context1 = repository.getInitialContext(); InitialContext context2 = repository.getInitialContext(); // Then verify(repository).createInitialContext(); assertThat(context1).isEqualTo(context); assertThat(context2).isEqualTo(context); } }