geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gosulli...@apache.org
Subject [geode] branch develop updated: GEODE-3127: add function execution to new client protocol. (#1357)
Date Fri, 02 Feb 2018 18:03:15 GMT
This is an automated email from the ASF dual-hosted git repository.

gosullivan pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 6011e09  GEODE-3127: add function execution to new client protocol. (#1357)
6011e09 is described below

commit 6011e094432c2e528d1c04912d63a7f51fa7c6f4
Author: Galen O'Sullivan <gosullivan@pivotal.io>
AuthorDate: Fri Feb 2 10:03:12 2018 -0800

    GEODE-3127: add function execution to new client protocol. (#1357)
    
    * GEODE-3127: add function execution to new client protocol.
    
    This only supports function execution on a region so far. It assumes the
    default result collector, which returns a list of results, so the response message returns a list of results.
    
    * MessageExecutionContext uses InternalCache instead of Cache
    * Remove super.setUp calls from operation handlers because the
      @Before annotation already ensures these are called before the
      @Before methods of child classes.
---
 .../client/protocol/ClientProtocolService.java     |   5 +-
 .../src/main/proto/v1/clientProtocol.proto         |   5 +
 .../src/main/proto/v1/function_API.proto           |  29 ++
 .../v1/LocatorMessageExecutionContext.java         |   4 +-
 .../protobuf/v1/MessageExecutionContext.java       |   4 +-
 .../protobuf/v1/ProtobufProtocolService.java       |   4 +-
 .../protobuf/v1/ProtobufSerializationService.java  |   6 +-
 .../protobuf/v1/ServerMessageExecutionContext.java |  12 +-
 ...uteFunctionOnRegionRequestOperationHandler.java | 135 ++++++++
 .../registry/ProtobufOperationContextRegistry.java |  13 +-
 .../internal/protocol/TestExecutionContext.java    |   4 +-
 .../v1/FunctionExecutionIntegrationTest.java       | 360 +++++++++++++++++++++
 ...onOnRegionRequestOperationHandlerJUnitTest.java | 161 +++++++++
 .../GetAllRequestOperationHandlerJUnitTest.java    |   2 -
 ...egionNamesRequestOperationHandlerJUnitTest.java |   6 +-
 .../GetRegionRequestOperationHandlerJUnitTest.java |   6 +-
 .../GetRequestOperationHandlerJUnitTest.java       |   2 -
 .../GetServerOperationHandlerJUnitTest.java        |   2 -
 .../v1/operations/OperationHandlerJUnitTest.java   |   5 +-
 .../PutAllRequestOperationHandlerJUnitTest.java    |   1 -
 .../PutRequestOperationHandlerJUnitTest.java       |   2 -
 .../RemoveRequestOperationHandlerJUnitTest.java    |   2 -
 22 files changed, 730 insertions(+), 40 deletions(-)

diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolService.java b/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolService.java
index d31a4d5..855cb09 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolService.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolService.java
@@ -16,8 +16,8 @@
 package org.apache.geode.internal.cache.client.protocol;
 
 import org.apache.geode.StatisticsFactory;
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.security.SecurityService;
 
 /**
@@ -32,7 +32,8 @@ public interface ClientProtocolService {
    * handshake has happened.
    *
    */
-  ClientProtocolProcessor createProcessorForCache(Cache cache, SecurityService securityService);
+  ClientProtocolProcessor createProcessorForCache(InternalCache cache,
+      SecurityService securityService);
 
   /**
    * Create a locator processor. The locator does not currently provide any authentication.
diff --git a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
index 21bc2fa..6bbe295 100644
--- a/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
+++ b/geode-protobuf-messages/src/main/proto/v1/clientProtocol.proto
@@ -25,6 +25,7 @@ import "v1/region_API.proto";
 import "v1/locator_API.proto";
 import "v1/basicTypes.proto";
 import "v1/connection_API.proto";
+import "v1/function_API.proto";
 
 message Message {
     oneof messageType {
@@ -46,6 +47,8 @@ message Request {
         GetRegionNamesRequest getRegionNamesRequest = 41;
         GetRegionRequest getRegionRequest = 42;
 
+        ExecuteFunctionOnRegionRequest executeFunctionOnRegionRequest = 43;
+
         AuthenticationRequest authenticationRequest = 100;
     }
 }
@@ -63,6 +66,8 @@ message Response {
         GetRegionNamesResponse getRegionNamesResponse = 41;
         GetRegionResponse getRegionResponse = 42;
 
+        ExecuteFunctionOnRegionResponse executeFunctionOnRegionResponse= 43;
+
         AuthenticationResponse authenticationResponse = 100;
 
         ErrorResponse errorResponse = 1000;
diff --git a/geode-protobuf-messages/src/main/proto/v1/function_API.proto b/geode-protobuf-messages/src/main/proto/v1/function_API.proto
new file mode 100644
index 0000000..77d2280
--- /dev/null
+++ b/geode-protobuf-messages/src/main/proto/v1/function_API.proto
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+syntax = "proto3";
+package org.apache.geode.internal.protocol.protobuf.v1;
+
+import "v1/basicTypes.proto";
+
+message ExecuteFunctionOnRegionRequest {
+    string functionID = 1;
+    string region = 2;
+    EncodedValue arguments = 3;
+    repeated EncodedValue keyFilter = 4;
+}
+
+message ExecuteFunctionOnRegionResponse {
+    repeated EncodedValue results = 1; // some functions don't return arguments.
+}
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/LocatorMessageExecutionContext.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/LocatorMessageExecutionContext.java
index 98908de..a38f49c 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/LocatorMessageExecutionContext.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/LocatorMessageExecutionContext.java
@@ -17,8 +17,8 @@ package org.apache.geode.internal.protocol.protobuf.v1;
 
 
 import org.apache.geode.annotations.Experimental;
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.Locator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.exception.InvalidExecutionContextException;
 import org.apache.geode.internal.protocol.protobuf.statistics.ClientStatistics;
 import org.apache.geode.internal.protocol.protobuf.v1.state.ProtobufConnectionStateProcessor;
@@ -41,7 +41,7 @@ public class LocatorMessageExecutionContext extends MessageExecutionContext {
    * @throws InvalidExecutionContextException if there is no cache available
    */
   @Override
-  public Cache getCache() throws InvalidExecutionContextException {
+  public InternalCache getCache() throws InvalidExecutionContextException {
     setConnectionStateProcessor(new ProtobufConnectionTerminatingStateProcessor());
     throw new InvalidExecutionContextException(
         "Operations on the locator should not to try to operate on a server");
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/MessageExecutionContext.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/MessageExecutionContext.java
index c97f596..80d560b 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/MessageExecutionContext.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/MessageExecutionContext.java
@@ -15,8 +15,8 @@
 package org.apache.geode.internal.protocol.protobuf.v1;
 
 import org.apache.geode.annotations.Experimental;
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.Locator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.exception.InvalidExecutionContextException;
 import org.apache.geode.internal.protocol.protobuf.statistics.ClientStatistics;
 import org.apache.geode.internal.protocol.protobuf.v1.state.ProtobufConnectionStateProcessor;
@@ -36,7 +36,7 @@ public abstract class MessageExecutionContext {
     return protobufConnectionStateProcessor;
   }
 
-  public abstract Cache getCache() throws InvalidExecutionContextException;
+  public abstract InternalCache getCache() throws InvalidExecutionContextException;
 
   public abstract Locator getLocator() throws InvalidExecutionContextException;
 
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufProtocolService.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufProtocolService.java
index 8d7d718..bfc2048 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufProtocolService.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufProtocolService.java
@@ -15,8 +15,8 @@
 package org.apache.geode.internal.protocol.protobuf.v1;
 
 import org.apache.geode.StatisticsFactory;
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.client.protocol.ClientProtocolProcessor;
 import org.apache.geode.internal.cache.client.protocol.ClientProtocolService;
 import org.apache.geode.internal.protocol.protobuf.ProtocolVersion;
@@ -38,7 +38,7 @@ public class ProtobufProtocolService implements ClientProtocolService {
   }
 
   @Override
-  public ClientProtocolProcessor createProcessorForCache(Cache cache,
+  public ClientProtocolProcessor createProcessorForCache(InternalCache cache,
       SecurityService securityService) {
     assert (statistics != null);
 
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufSerializationService.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufSerializationService.java
index 40a9cd7..5442776 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufSerializationService.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufSerializationService.java
@@ -33,11 +33,15 @@ public class ProtobufSerializationService implements SerializationService<BasicT
    * @param value the value to be encoded
    *
    * @return EncodedValue message with the serialized value
-   * @throws EncodingException
    */
   @Override
   public BasicTypes.EncodedValue encode(Object value) throws EncodingException {
+    if (value == null) {
+      return BasicTypes.EncodedValue.getDefaultInstance();
+    }
+
     BasicTypes.EncodedValue.Builder builder = BasicTypes.EncodedValue.newBuilder();
+
     try {
       ProtobufEncodingTypes protobufEncodingTypes = ProtobufEncodingTypes.valueOf(value.getClass());
       switch (protobufEncodingTypes) {
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ServerMessageExecutionContext.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ServerMessageExecutionContext.java
index bf14b43..1abd1ad 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ServerMessageExecutionContext.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ServerMessageExecutionContext.java
@@ -17,19 +17,19 @@ package org.apache.geode.internal.protocol.protobuf.v1;
 
 
 import org.apache.geode.annotations.Experimental;
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.Locator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.exception.InvalidExecutionContextException;
 import org.apache.geode.internal.protocol.protobuf.statistics.ClientStatistics;
 import org.apache.geode.internal.protocol.protobuf.v1.state.ProtobufConnectionStateProcessor;
 
 @Experimental
 public class ServerMessageExecutionContext extends MessageExecutionContext {
-  private final Cache cache;
+  private final InternalCache cache;
 
-  public ServerMessageExecutionContext(Cache cache, ClientStatistics statistics,
-      ProtobufConnectionStateProcessor initialProtobufConnectionStateProcessor) {
-    super(statistics, initialProtobufConnectionStateProcessor);
+  public ServerMessageExecutionContext(InternalCache cache, ClientStatistics statistics,
+      ProtobufConnectionStateProcessor initialConnectionStateProcessor) {
+    super(statistics, initialConnectionStateProcessor);
     this.cache = cache;
   }
 
@@ -40,7 +40,7 @@ public class ServerMessageExecutionContext extends MessageExecutionContext {
    * @throws InvalidExecutionContextException if there is no cache available
    */
   @Override
-  public Cache getCache() throws InvalidExecutionContextException {
+  public InternalCache getCache() throws InvalidExecutionContextException {
     return cache;
   }
 
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandler.java
new file mode 100644
index 0000000..932db99
--- /dev/null
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandler.java
@@ -0,0 +1,135 @@
+/*
+ * 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.internal.protocol.protobuf.v1.operations;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionException;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.internal.exception.InvalidExecutionContextException;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.protocol.operations.ProtobufOperationHandler;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
+import org.apache.geode.internal.protocol.protobuf.v1.Failure;
+import org.apache.geode.internal.protocol.protobuf.v1.FunctionAPI;
+import org.apache.geode.internal.protocol.protobuf.v1.MessageExecutionContext;
+import org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import org.apache.geode.internal.protocol.protobuf.v1.Success;
+import org.apache.geode.internal.protocol.protobuf.v1.serialization.exception.EncodingException;
+import org.apache.geode.internal.protocol.protobuf.v1.state.exception.ConnectionStateException;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.security.NotAuthorizedException;
+
+public class ExecuteFunctionOnRegionRequestOperationHandler implements
+    ProtobufOperationHandler<FunctionAPI.ExecuteFunctionOnRegionRequest, FunctionAPI.ExecuteFunctionOnRegionResponse> {
+  @Override
+  public Result<FunctionAPI.ExecuteFunctionOnRegionResponse, ClientProtocol.ErrorResponse> process(
+      ProtobufSerializationService serializationService,
+      FunctionAPI.ExecuteFunctionOnRegionRequest request,
+      MessageExecutionContext messageExecutionContext)
+      throws InvalidExecutionContextException, ConnectionStateException {
+
+    final String functionID = request.getFunctionID();
+    final String regionName = request.getRegion();
+
+    final Function<?> function = FunctionService.getFunction(functionID);
+    if (function == null) {
+      return Failure.of(ClientProtocol.ErrorResponse.newBuilder()
+          .setError(BasicTypes.Error.newBuilder().setErrorCode(BasicTypes.ErrorCode.INVALID_REQUEST)
+              .setMessage("Function with ID \"" + functionID + "\" not found").build())
+          .build());
+    }
+
+    final Region<Object, Object> region = messageExecutionContext.getCache().getRegion(regionName);
+    if (region == null) {
+      return Failure.of(ClientProtocol.ErrorResponse.newBuilder()
+          .setError(BasicTypes.Error.newBuilder().setErrorCode(BasicTypes.ErrorCode.INVALID_REQUEST)
+              .setMessage("Region \"" + regionName + "\" not found"))
+          .build());
+    }
+
+    final SecurityService securityService = messageExecutionContext.getCache().getSecurityService();
+
+    try {
+      // check security for function.
+      function.getRequiredPermissions(regionName).forEach(securityService::authorize);
+    } catch (NotAuthorizedException ex) {
+      return Failure.of(ClientProtocol.ErrorResponse.newBuilder()
+          .setError(BasicTypes.Error.newBuilder()
+              .setMessage("Authorization failed for function \"" + functionID + "\"")
+              .setErrorCode(BasicTypes.ErrorCode.AUTHORIZATION_FAILED))
+          .build());
+    }
+
+    try {
+      Execution execution = FunctionService.onRegion(region);
+
+      final Object arguments = serializationService.decode(request.getArguments());
+
+      if (arguments != null) {
+        execution = execution.setArguments(arguments);
+      }
+
+      execution = execution.withFilter(parseFilter(serializationService, request));
+
+      final ResultCollector<Object, List<Object>> resultCollector = execution.execute(functionID);
+
+      if (function.hasResult()) {
+        List<Object> results = resultCollector.getResult();
+
+        final FunctionAPI.ExecuteFunctionOnRegionResponse.Builder responseMessage =
+            FunctionAPI.ExecuteFunctionOnRegionResponse.newBuilder();
+        for (Object result : results) {
+          responseMessage.addResults(serializationService.encode(result));
+        }
+        return Success.of(responseMessage.build());
+      } else {
+        // This is fire and forget.
+        return Success.of(FunctionAPI.ExecuteFunctionOnRegionResponse.newBuilder().build());
+      }
+    } catch (FunctionException ex) {
+      return Failure.of(ClientProtocol.ErrorResponse.newBuilder()
+          .setError(BasicTypes.Error.newBuilder().setErrorCode(BasicTypes.ErrorCode.SERVER_ERROR)
+              .setMessage("Function execution failed: " + ex.toString()))
+          .build());
+    } catch (EncodingException ex) {
+      return Failure.of(ClientProtocol.ErrorResponse.newBuilder()
+          .setError(BasicTypes.Error.newBuilder().setErrorCode(BasicTypes.ErrorCode.SERVER_ERROR)
+              .setMessage("Encoding failed: " + ex.toString()))
+          .build());
+    }
+  }
+
+  private Set<Object> parseFilter(ProtobufSerializationService serializationService,
+      FunctionAPI.ExecuteFunctionOnRegionRequest request) throws EncodingException {
+    List<BasicTypes.EncodedValue> encodedFilter = request.getKeyFilterList();
+    Set<Object> filter = new HashSet<>();
+
+    for (BasicTypes.EncodedValue filterKey : encodedFilter) {
+      filter.add(serializationService.decode(filterKey));
+    }
+    return filter;
+  }
+}
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
index 03c6f70..9068486 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/registry/ProtobufOperationContextRegistry.java
@@ -22,6 +22,7 @@ import org.apache.geode.annotations.Experimental;
 import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
 import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol.Request.RequestAPICase;
 import org.apache.geode.internal.protocol.protobuf.v1.ProtobufOperationContext;
+import org.apache.geode.internal.protocol.protobuf.v1.operations.ExecuteFunctionOnRegionRequestOperationHandler;
 import org.apache.geode.internal.protocol.protobuf.v1.operations.GetAllRequestOperationHandler;
 import org.apache.geode.internal.protocol.protobuf.v1.operations.GetRegionNamesRequestOperationHandler;
 import org.apache.geode.internal.protocol.protobuf.v1.operations.GetRegionRequestOperationHandler;
@@ -51,8 +52,7 @@ public class ProtobufOperationContextRegistry {
         new ProtobufOperationContext<>(ClientProtocol.Request::getAuthenticationRequest,
             new AuthenticationRequestOperationHandler(),
             opsResp -> ClientProtocol.Response.newBuilder().setAuthenticationResponse(opsResp),
-            new ResourcePermission(ResourcePermission.Resource.DATA,
-                ResourcePermission.Operation.READ)));
+            new ResourcePermission(ResourcePermission.NULL, ResourcePermission.NULL)));
 
     operationContexts.put(RequestAPICase.GETREQUEST,
         new ProtobufOperationContext<>(ClientProtocol.Request::getGetRequest,
@@ -109,5 +109,14 @@ public class ProtobufOperationContextRegistry {
             opsResp -> ClientProtocol.Response.newBuilder().setGetServerResponse(opsResp),
             new ResourcePermission(ResourcePermission.Resource.CLUSTER,
                 ResourcePermission.Operation.READ)));
+
+    operationContexts.put(RequestAPICase.EXECUTEFUNCTIONONREGIONREQUEST,
+        new ProtobufOperationContext<>(ClientProtocol.Request::getExecuteFunctionOnRegionRequest,
+            new ExecuteFunctionOnRegionRequestOperationHandler(),
+            opsResp -> ClientProtocol.Response.newBuilder()
+                .setExecuteFunctionOnRegionResponse(opsResp),
+            // Resource permissions get handled per-function, since they have varying permission
+            // requirements.
+            new ResourcePermission(ResourcePermission.NULL, ResourcePermission.NULL)));
   }
 }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/TestExecutionContext.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/TestExecutionContext.java
index c5a373a..1a4c3f5 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/TestExecutionContext.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/TestExecutionContext.java
@@ -14,8 +14,8 @@
  */
 package org.apache.geode.internal.protocol;
 
-import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.protocol.protobuf.statistics.NoOpStatistics;
 import org.apache.geode.internal.protocol.protobuf.v1.LocatorMessageExecutionContext;
 import org.apache.geode.internal.protocol.protobuf.v1.MessageExecutionContext;
@@ -23,7 +23,7 @@ import org.apache.geode.internal.protocol.protobuf.v1.ServerMessageExecutionCont
 import org.apache.geode.internal.protocol.protobuf.v1.state.NoSecurityProtobufConnectionStateProcessor;
 
 public class TestExecutionContext {
-  public static MessageExecutionContext getNoAuthCacheExecutionContext(Cache cache) {
+  public static MessageExecutionContext getNoAuthCacheExecutionContext(InternalCache cache) {
     return new ServerMessageExecutionContext(cache, new NoOpStatistics(),
         new NoSecurityProtobufConnectionStateProcessor());
   }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/FunctionExecutionIntegrationTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/FunctionExecutionIntegrationTest.java
new file mode 100644
index 0000000..0fc5e68
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/FunctionExecutionIntegrationTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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.internal.protocol.protobuf.v1;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.awaitility.Awaitility;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.DataPolicy;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionFactory;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.cache.execute.FunctionException;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.RegionFunctionContext;
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.ConfigurationProperties;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.management.internal.security.ResourceConstants;
+import org.apache.geode.security.ResourcePermission;
+import org.apache.geode.security.SecurityManager;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class FunctionExecutionIntegrationTest {
+  private static final String TEST_REGION = "testRegion";
+  private static final String TEST_FUNCTION_ID = "testFunction";
+  public static final String SECURITY_PRINCIPAL = "principle";
+  private ProtobufSerializationService serializationService;
+  private Socket socket;
+  private Cache cache;
+  private SecurityManager securityManager;
+
+  @Before
+  public void setUp() throws Exception {
+    CacheFactory cacheFactory = new CacheFactory(new Properties());
+    cacheFactory.set(ConfigurationProperties.MCAST_PORT, "0");
+    cacheFactory.set(ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION, "false");
+    cacheFactory.set(ConfigurationProperties.USE_CLUSTER_CONFIGURATION, "false");
+
+    securityManager = mock(SecurityManager.class);
+    cacheFactory.setSecurityManager(securityManager);
+    when(securityManager.authenticate(any())).thenReturn(SECURITY_PRINCIPAL);
+    when(securityManager.authorize(eq(SECURITY_PRINCIPAL), any())).thenReturn(true);
+
+    cache = cacheFactory.create();
+
+    CacheServer cacheServer = cache.addCacheServer();
+    int cacheServerPort = AvailablePortHelper.getRandomAvailableTCPPort();
+    cacheServer.setPort(cacheServerPort);
+    cacheServer.start();
+
+    RegionFactory<Object, Object> regionFactory = cache.createRegionFactory();
+    regionFactory.setDataPolicy(DataPolicy.PARTITION);
+    Region<Object, Object> testRegion = regionFactory.create(TEST_REGION);
+
+
+    System.setProperty("geode.feature-protobuf-protocol", "true");
+
+    socket = new Socket("localhost", cacheServerPort);
+
+    Awaitility.await().atMost(5, TimeUnit.SECONDS).until(socket::isConnected);
+
+    MessageUtil.performAndVerifyHandshake(socket);
+
+    serializationService = new ProtobufSerializationService();
+  }
+
+  private static class TestFunction<T> implements Function<T> {
+    private final java.util.function.Function<FunctionContext<T>, Object> executeFunction;
+    // non-null iff function has been executed.
+    private final AtomicReference<FunctionContext> context = new AtomicReference<>();
+    private final boolean hasResult;
+
+    TestFunction() {
+      this.executeFunction = arg -> null;
+      this.hasResult = true;
+    }
+
+    TestFunction(java.util.function.Function<FunctionContext<T>, Object> executeFunction,
+        boolean hasResult) {
+      this.executeFunction = executeFunction;
+      this.hasResult = hasResult;
+    }
+
+    @Override
+    public String getId() {
+      return TEST_FUNCTION_ID;
+    }
+
+    @Override
+    public void execute(FunctionContext<T> context) {
+      this.context.set(context);
+      context.getResultSender().lastResult(executeFunction.apply(context));
+    }
+
+    @Override
+    public boolean hasResult() {
+      return hasResult;
+    }
+
+    @Override
+    public boolean isHA() {
+      // set for testing; we shouldn't need to test with isHA true because that's function service
+      // details.
+      return false;
+    }
+
+    FunctionContext getContext() {
+      return context.get();
+    }
+  }
+
+  @After
+  public void tearDown() {
+    cache.close();
+    try {
+      socket.close();
+    } catch (IOException ignore) {
+    }
+    FunctionService.unregisterFunction(TEST_FUNCTION_ID);
+  }
+
+  @Test
+  public void handlesNoResultFunction() throws IOException {
+    TestFunction<Object> testFunction = new TestFunction<>(context -> null, false);
+    FunctionService.registerFunction(testFunction);
+    final ClientProtocol.Message responseMessage = authenticateAndSendMessage();
+
+    assertNotNull(responseMessage);
+    assertEquals(ClientProtocol.Message.MessageTypeCase.RESPONSE,
+        responseMessage.getMessageTypeCase());
+    final ClientProtocol.Response response = responseMessage.getResponse();
+    assertEquals(ClientProtocol.Response.ResponseAPICase.EXECUTEFUNCTIONONREGIONRESPONSE,
+        response.getResponseAPICase());
+    final FunctionAPI.ExecuteFunctionOnRegionResponse executeFunctionOnRegionResponse =
+        response.getExecuteFunctionOnRegionResponse();
+
+    assertEquals(0, executeFunctionOnRegionResponse.getResultsCount());
+
+    Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> testFunction.getContext() != null);
+  }
+
+  @Test
+  public void handlesResultFunction() throws Exception {
+    final TestFunction<Object> testFunction =
+        new TestFunction<>(functionContext -> Integer.valueOf(22), true);
+    FunctionService.registerFunction(testFunction);
+    final ClientProtocol.Message responseMessage = authenticateAndSendMessage();
+
+    final FunctionAPI.ExecuteFunctionOnRegionResponse executeFunctionOnRegionResponse =
+        getFunctionResponse(responseMessage);
+
+    assertEquals(1, executeFunctionOnRegionResponse.getResultsCount());
+
+    final Object responseValue =
+        serializationService.decode(executeFunctionOnRegionResponse.getResults(0));
+    assertTrue(responseValue instanceof Integer);
+    assertEquals(22, responseValue);
+  }
+
+  @Test
+  public void handlesException() throws IOException {
+    final TestFunction<Object> testFunction = new TestFunction<>(context -> {
+      throw new FunctionException();
+    }, true);
+    FunctionService.registerFunction(testFunction);
+
+    final ClientProtocol.Message message = authenticateAndSendMessage();
+
+    assertEquals(ClientProtocol.Message.MessageTypeCase.RESPONSE, message.getMessageTypeCase());
+    assertEquals(ClientProtocol.Response.ResponseAPICase.ERRORRESPONSE,
+        message.getResponse().getResponseAPICase());
+    final BasicTypes.Error error = message.getResponse().getErrorResponse().getError();
+    assertEquals(BasicTypes.ErrorCode.SERVER_ERROR, error.getErrorCode());
+  }
+
+  @Test
+  public void handlesObjectThatCannotBeDecoded() throws IOException {
+    final TestFunction<Object> testFunction = new TestFunction<>(context -> {
+      return new Object();
+    }, true);
+    FunctionService.registerFunction(testFunction);
+
+    final ClientProtocol.Message message = authenticateAndSendMessage();
+
+
+    assertEquals(ClientProtocol.Message.MessageTypeCase.RESPONSE, message.getMessageTypeCase());
+    assertEquals(ClientProtocol.Response.ResponseAPICase.ERRORRESPONSE,
+        message.getResponse().getResponseAPICase());
+    final BasicTypes.Error error = message.getResponse().getErrorResponse().getError();
+
+    assertEquals(BasicTypes.ErrorCode.SERVER_ERROR, error.getErrorCode());
+
+  }
+
+  @Test
+  public void handlesNullReturnValues() throws Exception {
+    final TestFunction<Object> testFunction = new TestFunction<>(functionContext -> null, true);
+    FunctionService.registerFunction(testFunction);
+    final ClientProtocol.Message responseMessage = authenticateAndSendMessage();
+
+    final FunctionAPI.ExecuteFunctionOnRegionResponse executeFunctionOnRegionResponse =
+        getFunctionResponse(responseMessage);
+
+    assertEquals(1, executeFunctionOnRegionResponse.getResultsCount());
+
+    final Object responseValue =
+        serializationService.decode(executeFunctionOnRegionResponse.getResults(0));
+    assertNull(responseValue);
+  }
+
+  @Test
+  public void argumentsArePassedToFunction() throws Exception {
+    final TestFunction<Object> testFunction =
+        new TestFunction<>(functionContext -> functionContext.getArguments(), true);
+    FunctionService.registerFunction(testFunction);
+    ClientProtocol.Message.Builder message = createRequestMessageBuilder(
+        FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder().setFunctionID(TEST_FUNCTION_ID)
+            .setRegion(TEST_REGION).setArguments(serializationService.encode("hello")));
+
+    authenticateWithServer();
+    final ClientProtocol.Message responseMessage = writeMessage(message.build());
+
+    FunctionAPI.ExecuteFunctionOnRegionResponse response = getFunctionResponse(responseMessage);
+
+    assertEquals("hello", serializationService.decode(response.getResults(0)));
+  }
+
+  @Test
+  public void filterIsPassedToFunction() throws Exception {
+    final TestFunction<Object> testFunction = new TestFunction<>(context -> "result", true);
+    FunctionService.registerFunction(testFunction);
+    Set<Object> expectedFilter = new HashSet<>(Arrays.asList("key1", "key2"));
+
+    final ClientProtocol.Message.Builder message = createRequestMessageBuilder(
+        FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder().setFunctionID(TEST_FUNCTION_ID)
+            .setRegion(TEST_REGION).addKeyFilter(serializationService.encode("key1"))
+            .addKeyFilter(serializationService.encode("key2")));
+
+    authenticateWithServer();
+    final ClientProtocol.Message responseMessage = writeMessage(message.build());
+
+    FunctionAPI.ExecuteFunctionOnRegionResponse response = getFunctionResponse(responseMessage);
+    assertEquals("result", serializationService.decode(response.getResults(0)));
+
+    final RegionFunctionContext context = (RegionFunctionContext) testFunction.getContext();
+
+    final Set<?> filter = context.getFilter();
+
+    assertEquals(expectedFilter, filter);
+
+  }
+
+  @Test
+  public void permissionsAreRequiredToExecute() throws IOException {
+    final ResourcePermission requiredPermission = new ResourcePermission(
+        ResourcePermission.Resource.DATA, ResourcePermission.Operation.MANAGE);
+
+    final TestFunction<Object> testFunction = new TestFunction<Object>() {
+      @Override
+      public Collection<ResourcePermission> getRequiredPermissions(String regionName) {
+        return Arrays.asList(requiredPermission);
+      }
+    };
+    FunctionService.registerFunction(testFunction);
+
+    when(securityManager.authenticate(any())).thenReturn(SECURITY_PRINCIPAL);
+
+    when(securityManager.authorize(eq(SECURITY_PRINCIPAL), eq(requiredPermission)))
+        .thenReturn(false);
+
+    final ClientProtocol.Message message = authenticateAndSendMessage();
+    assertEquals("message=" + message, BasicTypes.ErrorCode.AUTHORIZATION_FAILED,
+        message.getResponse().getErrorResponse().getError().getErrorCode());
+
+    verify(securityManager).authorize(eq(SECURITY_PRINCIPAL), eq(requiredPermission));
+  }
+
+  private FunctionAPI.ExecuteFunctionOnRegionResponse getFunctionResponse(
+      ClientProtocol.Message responseMessage) {
+    assertEquals(responseMessage.getResponse().toString(),
+        ClientProtocol.Response.ResponseAPICase.EXECUTEFUNCTIONONREGIONRESPONSE,
+        responseMessage.getResponse().getResponseAPICase());
+    return responseMessage.getResponse().getExecuteFunctionOnRegionResponse();
+  }
+
+  private void authenticateWithServer() throws IOException {
+    ClientProtocol.Message.Builder request = ClientProtocol.Message.newBuilder()
+        .setRequest(ClientProtocol.Request.newBuilder()
+            .setAuthenticationRequest(ConnectionAPI.AuthenticationRequest.newBuilder()
+                .putCredentials(ResourceConstants.USER_NAME, "someuser")
+                .putCredentials(ResourceConstants.PASSWORD, "somepassword")));
+
+    ClientProtocol.Message response = writeMessage(request.build());
+    assertEquals(response.toString(), true,
+        response.getResponse().getAuthenticationResponse().getAuthenticated());
+  }
+
+  private ClientProtocol.Message authenticateAndSendMessage() throws IOException {
+    authenticateWithServer();
+
+    final ClientProtocol.Message request =
+        createRequestMessageBuilder(FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder()
+            .setFunctionID(TEST_FUNCTION_ID).setRegion(TEST_REGION)).build();
+
+    return writeMessage(request);
+  }
+
+
+  private ClientProtocol.Message.Builder createRequestMessageBuilder(
+      FunctionAPI.ExecuteFunctionOnRegionRequest.Builder functionRequest) {
+    return ClientProtocol.Message.newBuilder().setRequest(
+        ClientProtocol.Request.newBuilder().setExecuteFunctionOnRegionRequest(functionRequest));
+  }
+
+  private ClientProtocol.Message writeMessage(ClientProtocol.Message request) throws IOException {
+    request.writeDelimitedTo(socket.getOutputStream());
+
+    return ClientProtocol.Message.parseDelimitedFrom(socket.getInputStream());
+  }
+
+}
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandlerJUnitTest.java
new file mode 100644
index 0000000..1384c3b
--- /dev/null
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/ExecuteFunctionOnRegionRequestOperationHandlerJUnitTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.internal.protocol.protobuf.v1.operations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.LocalRegion;
+import org.apache.geode.internal.protocol.protobuf.statistics.ProtobufClientStatistics;
+import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
+import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
+import org.apache.geode.internal.protocol.protobuf.v1.Failure;
+import org.apache.geode.internal.protocol.protobuf.v1.FunctionAPI;
+import org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
+import org.apache.geode.internal.protocol.protobuf.v1.Result;
+import org.apache.geode.internal.protocol.protobuf.v1.ServerMessageExecutionContext;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.management.internal.security.ResourcePermissions;
+import org.apache.geode.security.NotAuthorizedException;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unfortunately, we can't test the happy path with a unit test, because the function service is
+ * static, and there's mocking function execution is too complicated.
+ */
+@Category(UnitTest.class)
+public class ExecuteFunctionOnRegionRequestOperationHandlerJUnitTest {
+  private static final String TEST_REGION = "testRegion";
+  private static final String TEST_FUNCTION_ID = "testFunction";
+  public static final String NOT_A_REGION = "notARegion";
+  private Region regionStub;
+  private InternalCache cacheStub;
+  private ExecuteFunctionOnRegionRequestOperationHandler operationHandler;
+  private ProtobufSerializationService serializationService;
+  private TestFunction function;
+
+  private static class TestFunction implements Function {
+    // non-null iff function has been executed.
+    private AtomicReference<FunctionContext> context = new AtomicReference<>();
+
+    @Override
+    public String getId() {
+      return TEST_FUNCTION_ID;
+    }
+
+    @Override
+    public void execute(FunctionContext context) {
+      this.context.set(context);
+      context.getResultSender().lastResult("result");
+    }
+
+    FunctionContext getContext() {
+      return context.get();
+    }
+  }
+
+  @Before
+  public void setUp() {
+    regionStub = mock(LocalRegion.class);
+    cacheStub = mock(InternalCache.class);
+    serializationService = new ProtobufSerializationService();
+
+    when(cacheStub.getRegion(TEST_REGION)).thenReturn(regionStub);
+    when(cacheStub.getSecurityService()).thenReturn(mock(SecurityService.class));
+
+
+
+    operationHandler = new ExecuteFunctionOnRegionRequestOperationHandler();
+
+    function = new TestFunction();
+    FunctionService.registerFunction(function);
+  }
+
+  @After
+  public void tearDown() {
+    FunctionService.unregisterFunction(TEST_FUNCTION_ID);
+  }
+
+  @Test
+  public void failsOnUnknownRegion() throws Exception {
+    final FunctionAPI.ExecuteFunctionOnRegionRequest request =
+        FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder().setFunctionID(TEST_FUNCTION_ID)
+            .setRegion(NOT_A_REGION).build();
+
+    final Result<FunctionAPI.ExecuteFunctionOnRegionResponse, ClientProtocol.ErrorResponse> result =
+        operationHandler.process(serializationService, request, mockedMessageExecutionContext());
+
+    assertTrue(result instanceof Failure);
+
+    verify(cacheStub).getRegion(NOT_A_REGION);
+  }
+
+  @Test
+  public void requiresPermissions() throws Exception {
+    final SecurityService securityService = mock(SecurityService.class);
+    doThrow(new NotAuthorizedException("we should catch this")).when(securityService)
+        .authorize(ResourcePermissions.DATA_WRITE);
+    when(cacheStub.getSecurityService()).thenReturn(securityService);
+
+    final FunctionAPI.ExecuteFunctionOnRegionRequest request =
+        FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder().setFunctionID(TEST_FUNCTION_ID)
+            .setRegion(TEST_REGION).build();
+
+    final Result<FunctionAPI.ExecuteFunctionOnRegionResponse, ClientProtocol.ErrorResponse> result =
+        operationHandler.process(serializationService, request, mockedMessageExecutionContext());
+
+    assertTrue(result instanceof Failure);
+
+    assertEquals(BasicTypes.ErrorCode.AUTHORIZATION_FAILED,
+        result.getErrorMessage().getError().getErrorCode());
+
+  }
+
+  @Test
+  public void functionNotFound() throws Exception {
+    final FunctionAPI.ExecuteFunctionOnRegionRequest request =
+        FunctionAPI.ExecuteFunctionOnRegionRequest.newBuilder().setFunctionID(TEST_FUNCTION_ID)
+            .setRegion(TEST_REGION).build();
+
+    FunctionService.unregisterFunction(TEST_FUNCTION_ID);
+
+    final Result<FunctionAPI.ExecuteFunctionOnRegionResponse, ClientProtocol.ErrorResponse> result =
+        operationHandler.process(serializationService, request, mockedMessageExecutionContext());
+
+    final ClientProtocol.ErrorResponse errorMessage = result.getErrorMessage();
+
+    assertEquals(BasicTypes.ErrorCode.INVALID_REQUEST, errorMessage.getError().getErrorCode());
+  }
+
+  private ServerMessageExecutionContext mockedMessageExecutionContext() {
+    return new ServerMessageExecutionContext(cacheStub, mock(ProtobufClientStatistics.class), null);
+  }
+}
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
index 4f3f94b..6a4d03e 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
@@ -57,8 +57,6 @@ public class GetAllRequestOperationHandlerJUnitTest extends OperationHandlerJUni
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     regionStub = mock(Region.class);
     when(regionStub.get(TEST_KEY1)).thenReturn(TEST_VALUE1);
     when(regionStub.get(TEST_KEY2)).thenReturn(TEST_VALUE2);
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
index a26c0ea..d2fbc7f 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
@@ -29,8 +29,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.Region;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.protocol.protobuf.v1.RegionAPI;
 import org.apache.geode.internal.protocol.protobuf.v1.Result;
 import org.apache.geode.internal.protocol.protobuf.v1.Success;
@@ -45,8 +45,6 @@ public class GetRegionNamesRequestOperationHandlerJUnitTest extends OperationHan
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     Region<String, String> region1Stub = mock(Region.class);
     when(region1Stub.getName()).thenReturn(TEST_REGION1);
     Region<String, String> region2Stub = mock(Region.class);
@@ -88,7 +86,7 @@ public class GetRegionNamesRequestOperationHandlerJUnitTest extends OperationHan
 
   @Test
   public void processReturnsNoCacheRegions() throws Exception {
-    Cache emptyCache = mock(Cache.class);;
+    InternalCache emptyCache = mock(InternalCache.class);
     when(emptyCache.rootRegions())
         .thenReturn(Collections.unmodifiableSet(new HashSet<Region<String, String>>()));
     Result result = operationHandler.process(serializationService,
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionRequestOperationHandlerJUnitTest.java
index fb3f8b3..2671224 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionRequestOperationHandlerJUnitTest.java
@@ -26,11 +26,11 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.DataPolicy;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.Scope;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
 import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
 import org.apache.geode.internal.protocol.protobuf.v1.Failure;
@@ -46,8 +46,6 @@ public class GetRegionRequestOperationHandlerJUnitTest extends OperationHandlerJ
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     region1Stub = mock(Region.class);
     when(region1Stub.getName()).thenReturn(TEST_REGION1);
 
@@ -87,7 +85,7 @@ public class GetRegionRequestOperationHandlerJUnitTest extends OperationHandlerJ
 
   @Test
   public void processReturnsNoCacheRegions() throws Exception {
-    Cache emptyCache = mock(Cache.class);
+    InternalCache emptyCache = mock(InternalCache.class);
     when(emptyCache.rootRegions())
         .thenReturn(Collections.unmodifiableSet(new HashSet<Region<String, String>>()));
     String unknownRegionName = "UNKNOWN_REGION";
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
index 52da737..bd0a416 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRequestOperationHandlerJUnitTest.java
@@ -47,8 +47,6 @@ public class GetRequestOperationHandlerJUnitTest extends OperationHandlerJUnitTe
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     Region regionStub = mock(Region.class);
     when(regionStub.get(TEST_KEY)).thenReturn(TEST_VALUE);
     when(regionStub.get(MISSING_KEY)).thenReturn(null);
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetServerOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetServerOperationHandlerJUnitTest.java
index f2f4ce8..415c7fb 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetServerOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetServerOperationHandlerJUnitTest.java
@@ -54,8 +54,6 @@ public class GetServerOperationHandlerJUnitTest extends OperationHandlerJUnitTes
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     operationHandler = new GetServerOperationHandler();
     internalLocatorMock = mock(InternalLocator.class);
     serverLocatorAdviseeMock = mock(ServerLocator.class);
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OperationHandlerJUnitTest.java
index 54d0f2c..e0a8649 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/OperationHandlerJUnitTest.java
@@ -27,12 +27,13 @@ import org.apache.geode.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
 public class OperationHandlerJUnitTest {
-  protected Cache cacheStub;
+  protected InternalCache cacheStub;
   protected ProtobufSerializationService serializationService;
   protected ProtobufOperationHandler operationHandler;
 
+  // if we name this setUp, then our children override, which is all kinds of annoying.
   @Before
-  public void setUp() throws Exception {
+  public void setUpForChildJUnitTests() throws Exception {
     cacheStub = mock(InternalCache.class);
     serializationService = new ProtobufSerializationService();
   }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutAllRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutAllRequestOperationHandlerJUnitTest.java
index a9f0488..de00034 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutAllRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutAllRequestOperationHandlerJUnitTest.java
@@ -57,7 +57,6 @@ public class PutAllRequestOperationHandlerJUnitTest extends OperationHandlerJUni
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
     regionMock = mock(Region.class);
     when(regionMock.put(TEST_INVALID_KEY, TEST_INVALID_VALUE))
         .thenThrow(new ClassCastException(EXCEPTION_TEXT));
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutRequestOperationHandlerJUnitTest.java
index 38895b8..4322bec 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/PutRequestOperationHandlerJUnitTest.java
@@ -50,8 +50,6 @@ public class PutRequestOperationHandlerJUnitTest extends OperationHandlerJUnitTe
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     regionMock = mock(Region.class);
     when(regionMock.put(TEST_KEY, TEST_VALUE)).thenReturn(1);
 
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/RemoveRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/RemoveRequestOperationHandlerJUnitTest.java
index c5f109e..e67ae04 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/RemoveRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/RemoveRequestOperationHandlerJUnitTest.java
@@ -49,8 +49,6 @@ public class RemoveRequestOperationHandlerJUnitTest extends OperationHandlerJUni
 
   @Before
   public void setUp() throws Exception {
-    super.setUp();
-
     regionStub = mock(Region.class);
     when(regionStub.remove(TEST_KEY)).thenReturn(TEST_VALUE);
     when(regionStub.containsKey(TEST_KEY)).thenReturn(true);

-- 
To stop receiving notification emails like this one, please contact
gosullivan@apache.org.

Mime
View raw message