DATAGEODE-144 - Add 'requiredPermissions' to @GemfireFunction annotation.
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2018 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.data.gemfire.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.apache.geode.cache.execute.Function;
|
||||
import org.apache.geode.cache.execute.FunctionService;
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
import org.springframework.data.gemfire.function.config.EnableGemfireFunctions;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests testing the registration of Apache Geode/Pivotal GemFire {@link Function Functions}
|
||||
* with required permissions specified using the {@link GemfireFunction} {@link Annotation}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.data.gemfire.function.annotation.GemfireFunction
|
||||
* @see org.springframework.data.gemfire.function.config.EnableGemfireFunctions
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
public class FunctionWithRequiredPermissionsRegistrationIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void functionsRegisteredWithRequiredPermissionsSuccessfully() {
|
||||
|
||||
Function function = FunctionService.getFunction("testFunctionWithRequiredPermissions");
|
||||
|
||||
assertThat(function).isNotNull();
|
||||
assertThat(function.getRequiredPermissions("test")).containsExactly(
|
||||
new ResourcePermission(ResourcePermission.Resource.CLUSTER, ResourcePermission.Operation.MANAGE),
|
||||
new ResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.READ, "Example")
|
||||
);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGemfireFunctions
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
TestFunctions testFunctions() {
|
||||
return new TestFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
static class TestFunctions {
|
||||
|
||||
@GemfireFunction(requiredPermissions = { "CLUSTER:MANAGE", "DATA:READ:Example" })
|
||||
public void testFunctionWithRequiredPermissions() { }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2018 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.data.gemfire.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.geode.security.ResourcePermission;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.data.gemfire.function.annotation.GemfireFunction;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link GemfireFunctionUtils}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.function.GemfireFunctionUtils
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GemfireFunctionUtilsUnitTests {
|
||||
|
||||
private final TestFunctions testFunctions = new TestFunctions();
|
||||
|
||||
private ResourcePermission newResourcePermission(ResourcePermission.Resource resource,
|
||||
ResourcePermission.Operation operation, ResourcePermission.Target target, String key) {
|
||||
|
||||
return new ResourcePermission(resource, operation, target.name(), key);
|
||||
}
|
||||
|
||||
private ResourcePermission newResourcePermission(ResourcePermission.Resource resource,
|
||||
ResourcePermission.Operation operation, String target, String key) {
|
||||
|
||||
return new ResourcePermission(resource, operation, target, key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gemfireFunctionAnnotatedMethodIsGemFireFunction() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isGemfireFunction(TestFunctions.class.getDeclaredMethod("testFunction")))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonGemfireFunctionAnnotatedMethodIsNotGemFireFunction() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isGemfireFunction(TestFunctions.class.getDeclaredMethod("nonFunction")))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchingGemFireFunctionReturnsTrue() throws Exception {
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("identifiedFunction"), "MyFunction")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonMatchingGemFireFunctionReturnsFalse() throws Exception {
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("identifiedFunction"), "YourFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("nonFunction"), "nonFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("requiredPermissionsFunction"), "MyFunction"))
|
||||
.isFalse();
|
||||
|
||||
assertThat(GemfireFunctionUtils.isMatchingGemfireFunction(
|
||||
TestFunctions.class.getDeclaredMethod("testFunction"), "MockFunction"))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvesFunctionIdFromGemfireFunctionIdAttribute() {
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes = new AnnotationAttributes();
|
||||
|
||||
gemfireFunctionAttributes.put("id", "2");
|
||||
|
||||
assertThat(GemfireFunctionUtils.resolveFunctionId(gemfireFunctionAttributes)).isEqualTo("2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unresolvableFunctionIdReturnsNull() {
|
||||
assertThat(GemfireFunctionUtils.resolveFunctionId(new AnnotationAttributes())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithBatchSize() throws Exception {
|
||||
|
||||
Method functionWithBatchSize = TestFunctions.class.getDeclaredMethod("functionWithBatchSize");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithBatchSize, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithBatchSize);
|
||||
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, functionWithBatchSize,
|
||||
gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getBatchSize()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void configureWithInvalidBatchSizeThrowsIllegalArgumentException() throws Exception {
|
||||
|
||||
Method functionWithInvalidBatchSize =
|
||||
TestFunctions.class.getDeclaredMethod("functionWithInvalidBatchSize");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithInvalidBatchSize, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithInvalidBatchSize);
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, functionWithInvalidBatchSize,
|
||||
gemfireFunctionAttributes, function);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("GemfireFunction.batchSize [-5] specified on [%1$s.%2$s] must be a non-negative value",
|
||||
testFunctions.getClass().getName(), functionWithInvalidBatchSize.getName());
|
||||
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoBatchSize() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureBatchSize(this.testFunctions, testFunction, gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getBatchSize()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithHighAvailability() throws Exception {
|
||||
|
||||
Method functionWithHighAvailability = TestFunctions.class.getDeclaredMethod("functionWithHighAvailability");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithHighAvailability, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithHighAvailability);
|
||||
|
||||
GemfireFunctionUtils.configureHighAvailability(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.isHA()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoHighAvailability() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureHighAvailability(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.isHA()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithResult() throws Exception {
|
||||
|
||||
Method functionWithResult = TestFunctions.class.getDeclaredMethod("functionWithResult");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionWithResult, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionWithResult);
|
||||
|
||||
GemfireFunctionUtils.configureHasResult(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.hasResult()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoResult() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureHasResult(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.hasResult()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithOptimizeForWrite() throws Exception {
|
||||
|
||||
Method functionOptimizedForWrite = TestFunctions.class.getDeclaredMethod("functionOptimizedForWrite");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(functionOptimizedForWrite, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, functionOptimizedForWrite);
|
||||
|
||||
GemfireFunctionUtils.configureOptimizeForWrite(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.optimizeForWrite()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithNoOptimizeForWrite() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureOptimizeForWrite(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.optimizeForWrite()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cofigureWithDefaultRequiredPermissions() throws Exception {
|
||||
|
||||
Method testFunction = TestFunctions.class.getDeclaredMethod("testFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(testFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, testFunction);
|
||||
|
||||
GemfireFunctionUtils.configureRequiredPermissions(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getRequiredPermissions("test")).containsExactly(
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.WRITE, (String) null, null)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWithRequiredPermissions() throws Exception {
|
||||
|
||||
Method requiredPermissionsFunction = TestFunctions.class.getDeclaredMethod("requiredPermissionsFunction");
|
||||
|
||||
AnnotationAttributes gemfireFunctionAttributes =
|
||||
GemfireFunctionUtils.getAnnotationAttributes(requiredPermissionsFunction, GemfireFunction.class);
|
||||
|
||||
PojoFunctionWrapper function = new PojoFunctionWrapper(this.testFunctions, requiredPermissionsFunction);
|
||||
|
||||
GemfireFunctionUtils.configureRequiredPermissions(gemfireFunctionAttributes, function);
|
||||
|
||||
assertThat(function.getRequiredPermissions("Example")).containsExactly(
|
||||
newResourcePermission(ResourcePermission.Resource.CLUSTER, ResourcePermission.Operation.MANAGE, (String) null, null),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.MANAGE, "System", null),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.READ, ResourcePermission.Target.QUERY, "ALL"),
|
||||
newResourcePermission(ResourcePermission.Resource.DATA, ResourcePermission.Operation.WRITE, "Example", "123")
|
||||
);
|
||||
}
|
||||
|
||||
public void testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(
|
||||
String resourcePermissionString) {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission(resourcePermissionString);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("ResourcePermission [%s] is required", resourcePermissionString);
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithNullStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithEmptyStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException("");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithBlankStringThrowsIllegalArgumentException() {
|
||||
testParseResourcePermissionWithInvalidArgumentThrowsIllegalArgumentException(" ");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithInvalidResourceThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission("SOCKET:OPEN");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("[SOCKET] is not a valid [%1$s] type; must be 1 of %2$s",
|
||||
ResourcePermission.Resource.class.getName(), Arrays.toString(ResourcePermission.Resource.values()));
|
||||
|
||||
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void parseResourcePermissionWithInvalidOperationThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
GemfireFunctionUtils.parseResourcePermission("DATA:COPY");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("[COPY] is not a valid [%1$s] type; must be 1 of %2$s",
|
||||
ResourcePermission.Operation.class.getName(), Arrays.toString(ResourcePermission.Operation.values()));
|
||||
|
||||
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseResourcePermissionIsSuccessful() {
|
||||
|
||||
ResourcePermission resourcePermission =
|
||||
GemfireFunctionUtils.parseResourcePermission("CLUSTER:MANAGE");
|
||||
|
||||
assertThat(resourcePermission).isNotNull();
|
||||
assertThat(resourcePermission.getResource()).isEqualTo(ResourcePermission.Resource.CLUSTER);
|
||||
assertThat(resourcePermission.getOperation()).isEqualTo(ResourcePermission.Operation.MANAGE);
|
||||
}
|
||||
|
||||
static class TestFunctions {
|
||||
|
||||
@GemfireFunction(batchSize = 10)
|
||||
void functionWithBatchSize() { }
|
||||
|
||||
@GemfireFunction(batchSize = -5)
|
||||
void functionWithInvalidBatchSize() { }
|
||||
|
||||
@GemfireFunction(HA = true)
|
||||
void functionWithHighAvailability() { }
|
||||
|
||||
@GemfireFunction(hasResult = true)
|
||||
void functionWithResult() { }
|
||||
|
||||
@GemfireFunction(optimizeForWrite = true)
|
||||
void functionOptimizedForWrite() { }
|
||||
|
||||
@GemfireFunction(id = "MyFunction")
|
||||
void identifiedFunction() { }
|
||||
|
||||
void nonFunction() { }
|
||||
|
||||
@GemfireFunction(requiredPermissions = {
|
||||
"CLUSTER:MANAGE",
|
||||
"DATA:MANAGE:System",
|
||||
"DATA:READ:QUERY:ALL",
|
||||
"DATA:WRITE:Example:123"
|
||||
})
|
||||
void requiredPermissionsFunction() { }
|
||||
|
||||
@GemfireFunction
|
||||
void testFunction() { }
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user