blob: b192ffc02beb1940152fbb86c10ff5716b01a9a3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.apache.geode.management.internal.cli.functions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.apache.shiro.subject.Subject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.apache.geode.cache.execute.Execution;
import org.apache.geode.cache.execute.Function;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.cache.execute.ResultSender;
import org.apache.geode.cache.query.RegionNotFoundException;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.InternalCacheForClientAccess;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.security.AuthenticationRequiredException;
public class UserFunctionExecutionTest {
private Object[] arguments;
private Execution execution;
private Function userFunction;
private UserFunctionExecution function;
private SecurityService securityService;
private ResultCollector resultCollector;
private FunctionContext<Object[]> context;
private ResultSender<Object> resultSender;
private InternalCacheForClientAccess filterCache;
private ArgumentCaptor<CliFunctionResult> resultCaptor;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
execution = mock(Execution.class);
userFunction = mock(Function.class);
context = mock(FunctionContext.class);
resultSender = mock(ResultSender.class);
function = spy(UserFunctionExecution.class);
securityService = mock(SecurityService.class);
resultCollector = mock(ResultCollector.class);
filterCache = mock(InternalCacheForClientAccess.class);
arguments = new Object[] {"TestFunction", "key1,key2", "TestResultCollector", "arg1,arg2",
"/TestRegion", new Properties()};
when(userFunction.getId()).thenReturn("TestFunction");
InternalCache cache = mock(InternalCache.class);
DistributedSystem distributedSystem = mock(InternalDistributedSystem.class);
DistributedMember distributedMember = mock(InternalDistributedMember.class);
when(distributedMember.getId()).thenReturn("MockMemberId");
when(distributedSystem.getDistributedMember()).thenReturn(distributedMember);
when(filterCache.getDistributedSystem()).thenReturn(distributedSystem);
when(cache.getSecurityService()).thenReturn(securityService);
when(cache.getCacheForProcessingClientRequests()).thenReturn(filterCache);
when(context.getCache()).thenReturn(cache);
when(context.getArguments()).thenReturn(arguments);
when(context.getResultSender()).thenReturn(resultSender);
when(execution.withFilter(any())).thenReturn(execution);
when(execution.setArguments(any())).thenReturn(execution);
when(execution.withCollector(any())).thenReturn(execution);
when(execution.execute(anyString())).thenReturn(resultCollector);
doReturn(false).when(function).loginRequired(securityService);
doReturn(userFunction).when(function).loadFunction("TestFunction");
doReturn(resultCollector).when(function).parseResultCollector("TestResultCollector");
doReturn(execution).when(function).buildExecution(any(), any());
resultCaptor = ArgumentCaptor.forClass(CliFunctionResult.class);
}
@Test
public void testDefaultAttributes() {
assertThat(function.isHA()).isFalse();
assertThat(function.getId()).isEqualTo(UserFunctionExecution.ID);
assertThat(function.getRequiredPermissions(anyString())).isEmpty();
}
@Test
public void parseArgumentsTest() {
assertThat(function.parseArguments(null)).isNull();
assertThat(function.parseArguments("")).isNull();
assertThat(function.parseArguments("arg1,arg2")).isNotNull()
.isEqualTo(new String[] {"arg1", "arg2"});
}
@Test
public void parseFiltersTest() {
assertThat(function.parseFilters(null)).isNotNull().isEmpty();
assertThat(function.parseFilters("")).isNotNull().isEmpty();
assertThat(function.parseFilters("key1,key2")).isNotNull().containsOnly("key1", "key2");
}
@Test
public void buildExecutionShouldThrowExceptionWhenRegionIsRequiredButItDoesNotExist()
throws Exception {
when(filterCache.getRegion("region")).thenReturn(null);
when(function.buildExecution(any(), any())).thenCallRealMethod();
assertThatThrownBy(() -> function.buildExecution(filterCache, "region"))
.isInstanceOf(RegionNotFoundException.class);
}
@Test
public void loginRequiredShouldReturnTrueWhenSubjectIsNull() {
when(securityService.getSubject()).thenReturn(null);
when(function.loginRequired(securityService)).thenCallRealMethod();
assertThat(function.loginRequired(securityService)).isTrue();
}
@Test
public void loginRequiredShouldReturnTrueWhenSubjectIsNotAuthenticated() {
Subject subject = mock(Subject.class);
when(subject.isAuthenticated()).thenReturn(false);
when(securityService.getSubject()).thenReturn(subject);
when(function.loginRequired(securityService)).thenCallRealMethod();
assertThat(function.loginRequired(securityService)).isTrue();
}
@Test
public void loginRequiredShouldReturnTrueWhenSecurityServiceFailsToLoadSubject() {
when(function.loginRequired(securityService)).thenCallRealMethod();
doThrow(new AuthenticationRequiredException("Dummy Exception")).when(securityService)
.getSubject();
assertThat(function.loginRequired(securityService)).isTrue();
}
@Test
public void loginRequiredShouldReturnFalseWhenSubjectIsAuthenticated() {
Subject subject = mock(Subject.class);
when(subject.isAuthenticated()).thenReturn(true);
when(securityService.getSubject()).thenReturn(subject);
when(function.loginRequired(securityService)).thenCallRealMethod();
assertThat(function.loginRequired(securityService)).isFalse();
}
@Test
public void executeShouldFailWhenNoArgumentsAreProvided() {
when(context.getArguments()).thenReturn(null);
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo("Could not retrieve arguments");
}
@Test
public void executeShouldFailWhenTargetFunctionCanNotBeLoaded() {
doReturn(null).when(function).loadFunction(anyString());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage())
.isEqualTo("Function : TestFunction is not registered on member.");
}
@Test
@SuppressWarnings("unchecked")
public void executeShouldFailWhenResultCollectorCanNotBeInstantiated() throws Exception {
CliFunctionResult result;
doThrow(new ClassNotFoundException("ClassNotFoundException")).when(function)
.parseResultCollector(anyString());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo(
"ResultCollector : TestResultCollector not found. Error : ClassNotFoundException");
reset(resultSender);
doThrow(new IllegalAccessException("IllegalAccessException")).when(function)
.parseResultCollector(anyString());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo(
"ResultCollector : TestResultCollector not found. Error : IllegalAccessException");
reset(resultSender);
doThrow(new InstantiationException("InstantiationException")).when(function)
.parseResultCollector(anyString());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo(
"ResultCollector : TestResultCollector not found. Error : InstantiationException");
reset(resultSender);
}
@Test
public void executeShouldFailWhenRegionIsSetAsArgumentButItDoesNotExist() throws Exception {
when(function.buildExecution(any(), any())).thenCallRealMethod();
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo("/TestRegion does not exist");
}
@Test
public void executeShouldFailWhenExecutorCanNotBeLoaded() throws Exception {
doReturn(null).when(function).buildExecution(any(), any());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isFalse();
assertThat(result.getStatusMessage()).isEqualTo(
"While executing function : TestFunction on member : MockMemberId one region : /TestRegion error occurred : Could not retrieve executor");
}
@Test
@SuppressWarnings("unchecked")
public void executeShouldProperlyConfigureExecutionContext() {
Set<String> filter = new HashSet<>();
filter.add("key1");
filter.add("key2");
arguments = new Object[] {"TestFunction", "key1,key2", "TestResultCollector", "arg1,arg2",
"/TestRegion", new Properties()};
when(context.getArguments()).thenReturn(arguments);
function.execute(context);
verify(execution, times(1)).withFilter(filter);
verify(execution, times(1)).withCollector(resultCollector);
verify(execution, times(1)).setArguments(new String[] {"arg1", "arg2"});
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult resultFullArguments = resultCaptor.getValue();
assertThat(resultFullArguments.isSuccessful()).isTrue();
reset(resultSender);
reset(execution);
arguments = new Object[] {"TestFunction", "", "", "", "", new Properties()};
when(context.getArguments()).thenReturn(arguments);
function.execute(context);
verify(execution, never()).withFilter(any());
verify(execution, never()).setArguments(any());
verify(execution, never()).withCollector(any());
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult resultNoArguments = resultCaptor.getValue();
assertThat(resultNoArguments.isSuccessful()).isTrue();
}
@Test
public void executeShouldWorkProperlyForFunctionsWithResults() {
when(userFunction.hasResult()).thenReturn(true);
doReturn(true).when(function).loginRequired(any());
when(resultCollector.getResult()).thenReturn(Arrays.asList("result1", "result2"));
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isTrue();
assertThat(result.getStatusMessage()).isEqualTo("[result1, result2]");
verify(securityService, times(1)).login(any());
verify(securityService, times(1)).logout();
}
@Test
public void executeShouldWorkProperlyForFunctionsWithoutResults() {
when(userFunction.hasResult()).thenReturn(false);
doReturn(true).when(function).loginRequired(any());
function.execute(context);
verify(resultSender, times(1)).lastResult(resultCaptor.capture());
CliFunctionResult result = resultCaptor.getValue();
assertThat(result.isSuccessful()).isTrue();
assertThat(result.getStatusMessage()).isEqualTo("[]");
verify(securityService, times(1)).login(any());
verify(securityService, times(1)).logout();
}
}