This is an automated email from the ASF dual-hosted git repository. jasonhuynh 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 6d9e026 GEODE-5884: Added new command and restored pre 1.8 region function behavior (#2829) 6d9e026 is described below commit 6d9e026feb584309dff269e593417082a71434fc Author: Jason Huynh <huyn...@gmail.com> AuthorDate: Tue Nov 13 15:16:48 2018 -0800 GEODE-5884: Added new command and restored pre 1.8 region function behavior (#2829) * Due to the refactor that caused us to lose wrapping of exceptions, the fix to GEODE-5884 cannot be applied to GEODE 1.0-1.7 clients * Adding new command class will allow clients to identify which function class it is expecting to execute and what behavior to expect --- .../cache/tier/sockets/CommandInitializer.java | 9 +- .../sockets/command/ExecuteRegionFunction66.java | 7 +- .../command/ExecuteRegionFunctionGeode18.java | 62 +++++++++ .../command/ExecuteRegionFunction66Test.java | 22 ++- ....java => ExecuteRegionFunctionGeode18Test.java} | 42 +++--- .../RollingUpgradeNonHAFunction.java | 150 +++++++++++++++++++++ 6 files changed, 251 insertions(+), 41 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java index 7b0ddc8..67d20c6 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CommandInitializer.java @@ -43,6 +43,7 @@ import org.apache.geode.internal.cache.tier.sockets.command.ExecuteFunction70; import org.apache.geode.internal.cache.tier.sockets.command.ExecuteRegionFunction; import org.apache.geode.internal.cache.tier.sockets.command.ExecuteRegionFunction65; import org.apache.geode.internal.cache.tier.sockets.command.ExecuteRegionFunction66; +import org.apache.geode.internal.cache.tier.sockets.command.ExecuteRegionFunctionGeode18; import org.apache.geode.internal.cache.tier.sockets.command.ExecuteRegionFunctionSingleHop; import org.apache.geode.internal.cache.tier.sockets.command.GatewayReceiverCommand; import org.apache.geode.internal.cache.tier.sockets.command.Get70; @@ -329,9 +330,13 @@ public class CommandInitializer { ALL_COMMANDS.put(Version.GEODE_150, commands); ALL_COMMANDS.put(Version.GEODE_160, commands); ALL_COMMANDS.put(Version.GEODE_170, commands); - ALL_COMMANDS.put(Version.GEODE_180, commands); - ALL_COMMANDS.put(Version.GEODE_190, commands); + Map<Integer, Command> geode18Commands = new HashMap<Integer, Command>(); + geode18Commands.putAll(ALL_COMMANDS.get(Version.GEODE_170)); + geode18Commands.put(MessageType.EXECUTE_REGION_FUNCTION, + ExecuteRegionFunctionGeode18.getCommand()); + ALL_COMMANDS.put(Version.GEODE_180, geode18Commands); + ALL_COMMANDS.put(Version.GEODE_190, geode18Commands); } public static Map<Integer, Command> getCommands(Version version) { diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66.java index 166d470..d6c701f 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66.java +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66.java @@ -60,7 +60,7 @@ public class ExecuteRegionFunction66 extends BaseCommand { return singleton; } - private ExecuteRegionFunction66() {} + ExecuteRegionFunction66() {} @Override public void cmdExecute(final Message clientMessage, final ServerConnection serverConnection, @@ -396,7 +396,6 @@ public class ExecuteRegionFunction66 extends BaseCommand { if (function instanceof String) { switch (functionState) { case AbstractExecution.NO_HA_HASRESULT_NO_OPTIMIZEFORWRITE: - execution.setWaitOnExceptionFlag(true); execution.execute((String) function).getResult(); break; case AbstractExecution.HA_HASRESULT_NO_OPTIMIZEFORWRITE: @@ -406,14 +405,10 @@ public class ExecuteRegionFunction66 extends BaseCommand { execution.execute((String) function).getResult(); break; case AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE: - execution.setWaitOnExceptionFlag(true); execution.execute((String) function).getResult(); break; } } else { - if (!functionObject.isHA()) { - execution.setWaitOnExceptionFlag(true); - } execution.execute(functionObject).getResult(); } } diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18.java new file mode 100644 index 0000000..386cd55 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18.java @@ -0,0 +1,62 @@ +/* + * 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.cache.tier.sockets.command; + + +import org.apache.geode.cache.execute.Function; +import org.apache.geode.internal.cache.execute.AbstractExecution; +import org.apache.geode.internal.cache.tier.Command; + +/** + * @since Geode 1.8 + */ +public class ExecuteRegionFunctionGeode18 extends ExecuteRegionFunction66 { + + private static final ExecuteRegionFunctionGeode18 singleton = new ExecuteRegionFunctionGeode18(); + + public static Command getCommand() { + return singleton; + } + + private ExecuteRegionFunctionGeode18() {} + + void executeFunctionWithResult(Object function, byte functionState, + Function<?> functionObject, AbstractExecution execution) { + if (function instanceof String) { + switch (functionState) { + case AbstractExecution.NO_HA_HASRESULT_NO_OPTIMIZEFORWRITE: + execution.setWaitOnExceptionFlag(true); + execution.execute((String) function).getResult(); + break; + case AbstractExecution.HA_HASRESULT_NO_OPTIMIZEFORWRITE: + execution.execute((String) function).getResult(); + break; + case AbstractExecution.HA_HASRESULT_OPTIMIZEFORWRITE: + execution.execute((String) function).getResult(); + break; + case AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE: + execution.setWaitOnExceptionFlag(true); + execution.execute((String) function).getResult(); + break; + } + } else { + if (!functionObject.isHA()) { + execution.setWaitOnExceptionFlag(true); + } + execution.execute(functionObject).getResult(); + } + } + +} diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java index f7d369e..24be2e9 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java @@ -67,37 +67,36 @@ public class ExecuteRegionFunction66Test { } @Test - public void executingFunctionByStringWithNoHAShouldSetWaitOnException() throws Exception { + public void executingFunctionInPreGeode18ByStringWithNoHAShouldNotSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); String functionName = "functionName"; when(execution.execute(functionName)).thenReturn(mock(ResultCollector.class)); this.executeRegionFunction66.executeFunctionWithResult(functionName, AbstractExecution.NO_HA_HASRESULT_NO_OPTIMIZEFORWRITE, functionObject, execution); - verify(execution, times(1)).setWaitOnExceptionFlag(true); + verify(execution, times(0)).setWaitOnExceptionFlag(true); } @Test - public void executingFunctionByStringWithNoHAWithOptimizeForWriteShouldSetWaitOnException() - throws Exception { + public void executingFunctionInPreGeode18ByStringWithNoHAWithOptimizeForWriteShouldNotSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); String functionName = "functionName"; when(execution.execute(functionName)).thenReturn(mock(ResultCollector.class)); this.executeRegionFunction66.executeFunctionWithResult(functionName, AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE, functionObject, execution); - verify(execution, times(1)).setWaitOnExceptionFlag(true); + verify(execution, times(0)).setWaitOnExceptionFlag(true); } @Test - public void executeFunctionObjectShouldSetWaitOnException() throws Exception { + public void executingFunctionObjectInPreGeode18ShouldNotSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); this.executeRegionFunction66.executeFunctionWithResult(functionObject, AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE, functionObject, execution); - verify(execution, times(1)).setWaitOnExceptionFlag(true); + verify(execution, times(0)).setWaitOnExceptionFlag(true); } @Test - public void generateNullArgumentMessageIfRegionIsNull() throws Exception { + public void generateNullArgumentMessageIfRegionIsNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); assertEquals("The input region for the execute function request is null", @@ -105,7 +104,7 @@ public class ExecuteRegionFunction66Test { } @Test - public void generateNullArgumentMessageIfFunctionIsNullAndRegionIsNotNull() throws Exception { + public void generateNullArgumentMessageIfFunctionIsNullAndRegionIsNotNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); assertEquals("The input function for the execute function request is null", @@ -165,7 +164,7 @@ public class ExecuteRegionFunction66Test { } @Test - public void getAuthorizedExecuteFunctionReturnsNullIfAuthorizationIsNull() throws Exception { + public void getAuthorizedExecuteFunctionReturnsNullIfAuthorizationIsNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); String functionName = "functionName"; @@ -177,8 +176,7 @@ public class ExecuteRegionFunction66Test { } @Test - public void getAuthorizedExecuteFunctionReturnsExecutionContextIfAuthorizeRequestIsNotNull() - throws Exception { + public void getAuthorizedExecuteFunctionReturnsExecutionContextIfAuthorizeRequestIsNotNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); String functionName = "functionName"; diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18Test.java similarity index 84% copy from geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java copy to geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18Test.java index f7d369e..cbeb5d6 100644 --- a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunction66Test.java +++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/command/ExecuteRegionFunctionGeode18Test.java @@ -46,20 +46,21 @@ import org.apache.geode.internal.security.AuthorizeRequest; import org.apache.geode.test.junit.categories.ClientServerTest; @Category({ClientServerTest.class}) -public class ExecuteRegionFunction66Test { +public class ExecuteRegionFunctionGeode18Test { private static final String FUNCTION_ID = "function_id"; @Mock private Function functionObject; - private ExecuteRegionFunction66 executeRegionFunction66; + private ExecuteRegionFunctionGeode18 executeRegionFunctionGeode18; @Rule public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); @Before public void setUp() throws Exception { - this.executeRegionFunction66 = (ExecuteRegionFunction66) ExecuteRegionFunction66.getCommand(); + this.executeRegionFunctionGeode18 = + (ExecuteRegionFunctionGeode18) ExecuteRegionFunctionGeode18.getCommand(); this.functionObject = mock(Function.class); when(this.functionObject.getId()).thenReturn(FUNCTION_ID); @@ -67,49 +68,48 @@ public class ExecuteRegionFunction66Test { } @Test - public void executingFunctionByStringWithNoHAShouldSetWaitOnException() throws Exception { + public void executingFunctionByStringWithNoHAShouldSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); String functionName = "functionName"; when(execution.execute(functionName)).thenReturn(mock(ResultCollector.class)); - this.executeRegionFunction66.executeFunctionWithResult(functionName, + this.executeRegionFunctionGeode18.executeFunctionWithResult(functionName, AbstractExecution.NO_HA_HASRESULT_NO_OPTIMIZEFORWRITE, functionObject, execution); verify(execution, times(1)).setWaitOnExceptionFlag(true); } @Test - public void executingFunctionByStringWithNoHAWithOptimizeForWriteShouldSetWaitOnException() - throws Exception { + public void executingFunctionByStringWithNoHAWithOptimizeForWriteShouldSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); String functionName = "functionName"; when(execution.execute(functionName)).thenReturn(mock(ResultCollector.class)); - this.executeRegionFunction66.executeFunctionWithResult(functionName, + this.executeRegionFunctionGeode18.executeFunctionWithResult(functionName, AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE, functionObject, execution); verify(execution, times(1)).setWaitOnExceptionFlag(true); } @Test - public void executeFunctionObjectShouldSetWaitOnException() throws Exception { + public void executeFunctionObjectShouldSetWaitOnException() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); - this.executeRegionFunction66.executeFunctionWithResult(functionObject, + this.executeRegionFunctionGeode18.executeFunctionWithResult(functionObject, AbstractExecution.NO_HA_HASRESULT_OPTIMIZEFORWRITE, functionObject, execution); verify(execution, times(1)).setWaitOnExceptionFlag(true); } @Test - public void generateNullArgumentMessageIfRegionIsNull() throws Exception { + public void generateNullArgumentMessageIfRegionIsNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); assertEquals("The input region for the execute function request is null", - this.executeRegionFunction66.generateNullArgumentMessage(null, null)); + this.executeRegionFunctionGeode18.generateNullArgumentMessage(null, null)); } @Test - public void generateNullArgumentMessageIfFunctionIsNullAndRegionIsNotNull() throws Exception { + public void generateNullArgumentMessageIfFunctionIsNullAndRegionIsNotNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); assertEquals("The input function for the execute function request is null", - this.executeRegionFunction66.generateNullArgumentMessage("someRegion", null)); + this.executeRegionFunctionGeode18.generateNullArgumentMessage("someRegion", null)); } @Test @@ -132,7 +132,7 @@ public class ExecuteRegionFunction66Test { when(clientMessage.getPart(8)).thenReturn(part2); when(clientMessage.getPart(9)).thenReturn(part3); int filterSize = 3; - Set filter = this.executeRegionFunction66.populateFilters(clientMessage, filterSize); + Set filter = this.executeRegionFunctionGeode18.populateFilters(clientMessage, filterSize); assertSame(filterSize, filter.size()); assertTrue(filter.contains(object1)); assertTrue(filter.contains(object2)); @@ -158,27 +158,27 @@ public class ExecuteRegionFunction66Test { when(clientMessage.getPart(7)).thenReturn(part1); when(clientMessage.getPart(8)).thenReturn(part2); when(clientMessage.getPart(9)).thenReturn(part3); - Set nodes = this.executeRegionFunction66.populateRemovedNodes(clientMessage, 3, 6); + Set nodes = this.executeRegionFunctionGeode18.populateRemovedNodes(clientMessage, 3, 6); assertTrue(nodes.contains(object1)); assertTrue(nodes.contains(object2)); assertTrue(nodes.contains(object3)); } @Test - public void getAuthorizedExecuteFunctionReturnsNullIfAuthorizationIsNull() throws Exception { + public void getAuthorizedExecuteFunctionReturnsNullIfAuthorizationIsNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); String functionName = "functionName"; String regionPath = "regionPath"; ExecuteFunctionOperationContext context = - executeRegionFunction66.getAuthorizedExecuteFunctionOperationContext(null, null, true, null, + executeRegionFunctionGeode18.getAuthorizedExecuteFunctionOperationContext(null, null, true, + null, functionName, regionPath); assertNull(context); } @Test - public void getAuthorizedExecuteFunctionReturnsExecutionContextIfAuthorizeRequestIsNotNull() - throws Exception { + public void getAuthorizedExecuteFunctionReturnsExecutionContextIfAuthorizeRequestIsNotNull() { AbstractExecution execution = mock(AbstractExecution.class); when(execution.execute(functionObject)).thenReturn(mock(ResultCollector.class)); String functionName = "functionName"; @@ -188,7 +188,7 @@ public class ExecuteRegionFunction66Test { .thenReturn(mock(ExecuteFunctionOperationContext.class)); ExecuteFunctionOperationContext context = - executeRegionFunction66.getAuthorizedExecuteFunctionOperationContext(null, null, true, + executeRegionFunctionGeode18.getAuthorizedExecuteFunctionOperationContext(null, null, true, request, functionName, regionPath); assertNotNull(context); } diff --git a/geode-core/src/upgradeTest/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeNonHAFunction.java b/geode-core/src/upgradeTest/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeNonHAFunction.java new file mode 100644 index 0000000..2fc56a4 --- /dev/null +++ b/geode-core/src/upgradeTest/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeNonHAFunction.java @@ -0,0 +1,150 @@ +/* + * 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.cache.rollingupgrade; + +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; +import static org.apache.geode.test.dunit.Assert.fail; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.Properties; + +import org.junit.Test; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.execute.Function; +import org.apache.geode.cache.execute.FunctionContext; +import org.apache.geode.cache.execute.FunctionInvocationTargetException; +import org.apache.geode.cache.execute.FunctionService; +import org.apache.geode.cache.execute.ResultCollector; +import org.apache.geode.cache30.CacheSerializableRunnable; +import org.apache.geode.distributed.ConfigurationProperties; +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.InternalLocator; +import org.apache.geode.internal.AvailablePortHelper; +import org.apache.geode.internal.Version; +import org.apache.geode.test.dunit.Host; +import org.apache.geode.test.dunit.NetworkUtils; +import org.apache.geode.test.dunit.VM; +import org.apache.geode.test.dunit.standalone.VersionManager; + +public class RollingUpgradeNonHAFunction extends RollingUpgrade2DUnitTestBase { + + @Test + public void functionExceptionsThrownFromDifferentVersionServerShouldCorrectlyWrapFunctionExceptionCauses() + throws Exception { + final Host host = Host.getHost(0); + VM currentServer1 = host.getVM(VersionManager.CURRENT_VERSION, 0); + VM oldServer = host.getVM(oldVersion, 1); + VM currentServer2 = host.getVM(VersionManager.CURRENT_VERSION, 2); + VM oldServerAndLocator = host.getVM(oldVersion, 3); + + String regionName = "cqs"; + + RegionShortcut shortcut = RegionShortcut.PARTITION; + + String serverHostName = NetworkUtils.getServerHostName(); + int port = AvailablePortHelper.getRandomAvailableTCPPort(); + try { + Properties props = getSystemProperties(); + props.put(ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER, + "org.apache.geode.internal.cache.rollingupgrade.**"); + props.remove(DistributionConfig.LOCATORS_NAME); + invokeRunnableInVMs(invokeStartLocatorAndServer(serverHostName, port, props), + oldServerAndLocator); + + // Locators before 1.4 handled configuration asynchronously. + // We must wait for configuration configuration to be ready, or confirm that it is disabled. + oldServerAndLocator.invoke( + () -> await() + .untilAsserted(() -> assertTrue( + !InternalLocator.getLocator().getConfig().getEnableClusterConfiguration() + || InternalLocator.getLocator().isSharedConfigurationRunning()))); + + props.put(DistributionConfig.LOCATORS_NAME, serverHostName + "[" + port + "]"); + invokeRunnableInVMs(invokeCreateCache(props), currentServer1, currentServer2, oldServer); + + currentServer1.invoke(invokeAssertVersion(Version.CURRENT_ORDINAL)); + currentServer2.invoke(invokeAssertVersion(Version.CURRENT_ORDINAL)); + + // create region + invokeRunnableInVMs(invokeCreateRegion(regionName, shortcut), currentServer1, currentServer2, + oldServer, oldServerAndLocator); + + // Locators before 1.4 handled configuration asynchronously. + // We must wait for configuration configuration to be ready, or confirm that it is disabled. + oldServerAndLocator.invoke( + () -> await() + .untilAsserted(() -> assertTrue( + !InternalLocator.getLocator().getConfig().getEnableClusterConfiguration() + || InternalLocator.getLocator().isSharedConfigurationRunning()))); + + putDataSerializableAndVerify(currentServer1, regionName, 0, 100, currentServer2, oldServer, + oldServerAndLocator); + runFunction("/" + regionName, currentServer1, + currentServer2, oldServer, oldServerAndLocator); + + } finally { + invokeRunnableInVMs(invokeCloseCache(), currentServer1, currentServer2, oldServer, + oldServerAndLocator); + } + } + + protected void runFunction(String queryString, VM... vms) { + for (VM vm : vms) { + vm.invoke(invokeAssertFunctionResults(queryString)); + } + } + + private CacheSerializableRunnable invokeAssertFunctionResults(final String queryString) { + return new CacheSerializableRunnable("execute: assertQueryResults") { + public void run2() { + try { + invokeAssertFunctionResult(RollingUpgrade2DUnitTestBase.cache, queryString); + } catch (Exception e) { + fail("Error asserting query results", e); + } + } + }; + } + + private static void invokeAssertFunctionResult(GemFireCache cache, String regionName) { + ResultCollector rc = null; + try { + rc = FunctionService.onRegion(cache.getRegion(regionName)).execute(new ExceptionalFunction()); + rc.getResult(); + fail("Function executed was expected to throw an exception"); + } catch (Exception e) { + assertNotNull(e.getCause()); + assertSame(FunctionInvocationTargetException.class, e.getCause().getClass()); + } + } + + private static class ExceptionalFunction implements Function { + + @Override + public void execute(FunctionContext context) { + throw new FunctionInvocationTargetException("This is an explicitly thrown test exception"); + } + + @Override + public boolean isHA() { + return false; + } + } + +}