You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2016/02/25 21:27:13 UTC
[25/50] [abbrv] incubator-geode git commit: Merge branch 'develop'
into feature/GEODE-17
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/HeadlessGfsh.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/HeadlessGfsh.java
index 0000000,f8b3fd4..03dcd7d
mode 000000,100644..100644
--- a/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/HeadlessGfsh.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/HeadlessGfsh.java
@@@ -1,0 -1,374 +1,374 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.cli;
+
+ import com.gemstone.gemfire.management.internal.cli.shell.Gfsh;
+ import com.gemstone.gemfire.management.internal.cli.shell.GfshConfig;
+ import com.gemstone.gemfire.management.internal.cli.shell.jline.GfshUnsupportedTerminal;
+ import jline.console.ConsoleReader;
+ import org.springframework.shell.core.ExitShellRequest;
+ import org.springframework.shell.event.ShellStatus.Status;
+
+ import java.io.BufferedWriter;
+ import java.io.ByteArrayOutputStream;
+ import java.io.File;
+ import java.io.FileDescriptor;
+ import java.io.FileInputStream;
+ import java.io.IOException;
+ import java.io.OutputStreamWriter;
+ import java.io.PrintStream;
+ import java.io.PrintWriter;
+ import java.io.Writer;
+ import java.util.Properties;
+ import java.util.concurrent.CountDownLatch;
+ import java.util.concurrent.LinkedBlockingQueue;
+ import java.util.concurrent.TimeUnit;
+ import java.util.concurrent.locks.Condition;
+ import java.util.concurrent.locks.Lock;
+ import java.util.concurrent.locks.ReentrantLock;
+ import java.util.logging.Level;
+
+
+ /**
+ * This is headless shell which can be used to submit random commands and get command-result It is used for commands
+ * testing but can be used as for anything like programmatically sending commands to operate on GemFire Distributed
+ * systems. TODO : Merge HeadlessGfsh and HeadlessGfshShell TODO : Provide constructor for optionally specifying
+ * GfshConfig to provide logDirectory and logLevel
+ *
+ * @author tushark
+ */
+ @SuppressWarnings("rawtypes")
+ public class HeadlessGfsh implements ResultHandler {
+
+ public static final String ERROR_RESULT = "_$_ERROR_RESULT";
+
+ private HeadlessGfshShell shell = null;
+ private LinkedBlockingQueue queue = new LinkedBlockingQueue<>();
+ private long timeout = 20;
+ public String outputString = null;
+
+ public HeadlessGfsh(String name, int timeout) throws ClassNotFoundException, IOException {
+ this(name, timeout, null);
+ }
+
+ public HeadlessGfsh(String name, int timeout, Properties envProps) throws ClassNotFoundException, IOException {
+ this.timeout = timeout;
+ System.setProperty("jline.terminal", GfshUnsupportedTerminal.class.getName());
+ this.shell = new HeadlessGfshShell(name, this);
+ this.shell.setEnvProperty(Gfsh.ENV_APP_RESULT_VIEWER, "non-basic");
+
+ if (envProps != null) {
+ for (String key : envProps.stringPropertyNames()) {
+ this.shell.setEnvProperty(key, envProps.getProperty(key));
+ }
+ }
+
+ // This allows us to avoid race conditions during startup - in particular a NPE on the ConsoleReader which is
+ // created in a separate thread during start()
+ CountDownLatch shellStarted = new CountDownLatch(1);
+ this.shell.addShellStatusListener((oldStatus, newStatus) -> {
+ if (newStatus.getStatus() == Status.STARTED) {
+ shellStarted.countDown();
+ }
+ });
+
+ this.shell.start();
+ this.setThreadLocalInstance();
+
+ try {
+ shellStarted.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace(System.out);
+ }
+ }
+
+ public void setThreadLocalInstance() {
+ shell.setThreadLocalInstance();
+ }
+
+ //TODO : Have non-blocking method also where we move executeCommand call to separate thread-pool
+ public boolean executeCommand(String command) {
+ boolean status = false;
+ try {
+ outputString = null;
+ status = shell.executeScriptLine(command);
+ } catch (Exception e) {
+ outputString = e.getMessage();
+ }
+ return status;
+ }
+
- int getCommandExecutionStatus() {
++ public int getCommandExecutionStatus() {
+ return shell.getCommandExecutionStatus();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void handleExecutionResult(Object result, String sysout) {
+ queue.add(result);
+ outputString = sysout;
+ }
+
+ public Object getResult() throws InterruptedException {
+ //Dont wait for when some command calls gfsh.stop();
+ if (shell.stopCalledThroughAPI) return null;
+ try {
+ Object result = queue.poll(timeout, TimeUnit.SECONDS);
+ queue.clear();
+ return result;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+
+ public void clear() {
+ queue.clear();
+ outputString = null;
+ }
+
+ public void clearEvents() {
+ queue.clear();
+ outputString = null;
+ }
+
+ public void terminate() {
+ shell.terminate();
+ }
+
+ public boolean isConnectedAndReady() {
+ return shell.isConnectedAndReady();
+ }
+
+ public String getErrorString() {
+ return shell.errorString;
+ }
+
+ public boolean hasError() {
+ return shell.hasError();
+ }
+
+ public String getError() {
+ return shell.errorString;
+ }
+
+ public static class HeadlessGfshShell extends Gfsh {
+
+ private ResultHandler handler = null;
+ private final Lock lock = new ReentrantLock();
+ private final Condition endOfShell = lock.newCondition();
+ private ByteArrayOutputStream output = null;
+ private String errorString = null;
+ private boolean hasError = false;
+ boolean stopCalledThroughAPI = false;
+
+ protected HeadlessGfshShell(String testName, ResultHandler handler) throws ClassNotFoundException, IOException {
+ super(false, new String[]{}, new HeadlessGfshConfig(testName));
+ this.handler = handler;
+ }
+
+ public void setThreadLocalInstance() {
+ gfshThreadLocal.set(this);
+ }
+
+ protected void handleExecutionResult(Object result) {
+ if (!result.equals(ERROR_RESULT)) {
+ super.handleExecutionResult(result);
+ handler.handleExecutionResult(result, output.toString());
+ output.reset();
+ } else {
+ //signal waiting queue with error condition with empty output
+ output.reset();
+ handler.handleExecutionResult(result, output.toString());
+ }
+ }
+
+ int getCommandExecutionStatus() {
+ return getLastExecutionStatus();
+ }
+
+ public void terminate() {
+ closeShell();
+ stopPromptLoop();
+ stop();
+ }
+
+ public void stop() {
+ stopCalledThroughAPI = true;
+ }
+
+ private void stopPromptLoop() {
+ lock.lock();
+ try {
+ endOfShell.signalAll();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public String getErrorString() {
+ return errorString;
+ }
+
+ public boolean hasError() {
+ return hasError;
+ }
+
+ /**
+ * We override this method just to fool runner thread in reading from nothing. It waits for Condition endOfShell
+ * which is signalled when terminate is called. This achieves clean shutdown of runner thread.
+ */
+ @Override
+ public void promptLoop() {
+ lock.lock();
+ try {
+ while (true) {
+ try {
+ endOfShell.await();
+ } catch (InterruptedException e) {
+ //e.printStackTrace();
+ }
+ this.exitShellRequest = ExitShellRequest.NORMAL_EXIT;
+ setShellStatus(Status.SHUTTING_DOWN);
+ break;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private static void setGfshOutErr(PrintStream outToUse) {
+ Gfsh.gfshout = outToUse;
+ Gfsh.gfsherr = outToUse;
+ }
+
+ /**
+ * This prints out error messages when Exceptions occur in shell. Capture it and set error flag=true and send
+ * ERROR_RESULT on the queue to signal thread waiting for CommandResult
+ */
+ @Override
+ public void logWarning(String message, Throwable t) {
+ super.logWarning(message, t);
+ errorString = message;
+ hasError = true;
+ //signal waiting queue with error condition
+ handleExecutionResult(ERROR_RESULT);
+ }
+
+ /**
+ * This prints out error messages when Exceptions occur in shell. Capture it and set error flag=true and send
+ * ERROR_RESULT on the queue to signal thread waiting for CommandResult
+ */
+ @Override
+ public void logSevere(String message, Throwable t) {
+ super.logSevere(message, t);
+ errorString = message;
+ hasError = true;
+ //signal waiting queue with error condition
+ handleExecutionResult(ERROR_RESULT);
+ }
+
+ /**
+ * Setup console-reader to capture Shell output
+ */
+ @Override
+ protected ConsoleReader createConsoleReader() {
+ try {
+ output = new ByteArrayOutputStream(1024 * 10);
+ PrintStream sysout = new PrintStream(output);
+ setGfshOutErr(sysout);
+ return new ConsoleReader(new FileInputStream(FileDescriptor.in), sysout);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+
+ /**
+ * HeadlessGfshConfig for tests. Taken from TestableGfsh
+ */
+ static class HeadlessGfshConfig extends GfshConfig {
+ {
+ // set vm as a gfsh vm
+ CliUtil.isGfshVM = true;
+ }
+
+ private File parentDir;
+ private String fileNamePrefix;
+ private String name;
+ private String generatedHistoryFileName = null;
+
+ public HeadlessGfshConfig(String name) {
+ this.name = name;
+
+ if (isDUnitTest(this.name)) {
+ fileNamePrefix = this.name;
+ } else {
+ fileNamePrefix = "non-hydra-client";
+ }
+
+ parentDir = new File("gfsh_files");
+ parentDir.mkdirs();
+ }
+
+ private static boolean isDUnitTest(String name) {
+ boolean isDUnitTest = false;
+ if (name != null) {
+ String[] split = name.split("_");
+ if (split.length != 0 && split[0].endsWith("DUnitTest")) {
+ isDUnitTest = true;
+ }
+ }
+ return isDUnitTest;
+ }
+
+ @Override
+ public String getLogFilePath() {
+ return new File(parentDir, getFileNamePrefix() + "-gfsh.log").getAbsolutePath();
+ }
+
+ private String getFileNamePrefix() {
+ String timeStamp = new java.sql.Time(System.currentTimeMillis()).toString();
+ timeStamp = timeStamp.replace(':', '_');
+ return fileNamePrefix + "-" + timeStamp;
+ }
+
+ @Override
+ public String getHistoryFileName() {
+ if (generatedHistoryFileName == null) {
+ String fileName = new File(parentDir, (getFileNamePrefix() + "-gfsh.history")).getAbsolutePath();
+ generatedHistoryFileName = fileName;
+ return fileName;
+ } else {
+ return generatedHistoryFileName;
+ }
+ }
+
+ @Override
+ public boolean isTestConfig() {
+ return true;
+ }
+
+ @Override
+ public Level getLogLevel() {
+ // Keep log level fine for tests
+ return Level.FINE;
+ }
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
index 0000000,e0f6915..b941b28
mode 000000,100644..100644
--- a/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
@@@ -1,0 -1,137 +1,144 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.cli.shell;
+
+ import static org.junit.Assert.*;
+
+ import java.util.List;
+
+ import org.junit.After;
+ import org.junit.Test;
+ import org.junit.experimental.categories.Category;
+ import org.springframework.shell.core.CommandMarker;
+ import org.springframework.shell.core.annotation.CliCommand;
+ import org.springframework.shell.core.annotation.CliOption;
+ import org.springframework.shell.event.ParseResult;
+
+ import com.gemstone.gemfire.management.cli.Result;
+ import com.gemstone.gemfire.management.internal.cli.CommandManager;
+ import com.gemstone.gemfire.management.internal.cli.GfshParser;
+ import com.gemstone.gemfire.management.internal.cli.annotation.CliArgument;
+ import com.gemstone.gemfire.management.cli.CliMetaData;
+ import com.gemstone.gemfire.management.cli.ConverterHint;
+ import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder;
+ import com.gemstone.gemfire.management.internal.cli.shell.Gfsh;
+ import com.gemstone.gemfire.management.internal.cli.shell.GfshConfig;
+ import com.gemstone.gemfire.management.internal.cli.shell.GfshExecutionStrategy;
++import com.gemstone.gemfire.management.internal.security.Resource;
++import com.gemstone.gemfire.management.internal.security.ResourceConstants;
++import com.gemstone.gemfire.management.internal.security.ResourceOperation;
+ import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+ /**
+ * GfshExecutionStrategyTest - Includes tests to for GfshExecutionStrategyTest
+ *
+ * @author apande
+ */
+ @Category(UnitTest.class)
+ public class GfshExecutionStrategyJUnitTest {
+ private static final String COMMAND1_NAME = "command1";
+ private static final String COMMAND1_NAME_ALIAS = "command1_alias";
+ private static final String COMMAND2_NAME = "command2";
+ private static final String COMMAND1_SUCESS = "Command1 Executed successfully";
+ private static final String COMMAND2_SUCESS = "Command2 Executed successfully";
+ private static final String COMMAND1_HELP = "help for " + COMMAND1_NAME;
+
+ @After
+ public void tearDown() {
+ CommandManager.clearInstance();
+ }
+
+ //tests execute method by executing dummy method command1
+ @Test
+ public void testGfshExecutionStartegyExecute() throws Exception {
+ CommandManager commandManager = CommandManager.getInstance();
+ assertNotNull("CommandManager should not be null.", commandManager);
+ commandManager.add(Commands.class.newInstance());
+ GfshParser parser = new GfshParser(commandManager);
+ String[] command1Names = ((CliCommand) Commands.class.getMethod(
+ COMMAND1_NAME).getAnnotation(CliCommand.class)).value();
+ String input =command1Names[0];
+ ParseResult parseResult = null;
+ parseResult = parser.parse(input);
+ String[] args = new String[] {command1Names[0] };
+ Gfsh gfsh = Gfsh.getInstance(false, args, new GfshConfig());
+ GfshExecutionStrategy gfshExecutionStrategy = new GfshExecutionStrategy(gfsh);
+ Result resultObject = (Result)gfshExecutionStrategy.execute(parseResult);
+ String str = resultObject.nextLine();
+ assertTrue(str.trim().equals(COMMAND1_SUCESS));
+ }
+
+ //tests isReadyForCommnads method by executing dummy method command1.
+ //TODO: this method is hard coded in source which may change in future. So this
+ //test should also be accordingly changed
+ @Test
+ public void testGfshExecutionStartegyIsReadyForCommands() throws Exception {
+ CommandManager commandManager = CommandManager.getInstance();
+ assertNotNull("CommandManager should not be null.", commandManager);
+ commandManager.add(Commands.class.newInstance());
+ String[] command1Names = ((CliCommand) Commands.class.getMethod(
+ COMMAND1_NAME).getAnnotation(CliCommand.class)).value();
+ String[] args = new String[] {command1Names[0] };
+ Gfsh gfsh = Gfsh.getInstance(false, args, new GfshConfig());
+ GfshExecutionStrategy gfshExecutionStrategy = new GfshExecutionStrategy(gfsh);
+ boolean ready = gfshExecutionStrategy.isReadyForCommands();
+ assertTrue(ready);
+ }
+
+ //represents class for dummy methods
+ public static class Commands implements CommandMarker {
+
+ @CliCommand(value = { COMMAND1_NAME, COMMAND1_NAME_ALIAS }, help = COMMAND1_HELP)
+ @CliMetaData(shellOnly = true )
++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
+ public static Result command1() {
+ return ResultBuilder.createInfoResult(COMMAND1_SUCESS);
+ }
+
+ @CliCommand(value = { COMMAND2_NAME })
+ @CliMetaData(shellOnly = false )
++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
+ public static Result command2() {
+ return ResultBuilder.createInfoResult(COMMAND2_SUCESS);
+ }
+
+ @CliCommand(value = { "testParamConcat" })
++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
+ public static Result testParamConcat(
+ @CliOption(key = { "string" })
+ String string,
+ @CliOption(key = { "stringArray" })
+ @CliMetaData(valueSeparator = ",")
+ String[] stringArray,
+ @CliOption(key = { "stringList" }, optionContext = ConverterHint.STRING_LIST)
+ @CliMetaData(valueSeparator = ",")
+ List<String> stringList, @CliOption(key = { "integer" })
+ Integer integer, @CliOption(key = { "colonArray" })
+ @CliMetaData(valueSeparator = ":")
+ String[] colonArray) {
+ return null;
+ }
+
+ @CliCommand(value = { "testMultiWordArg" })
++ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
+ public static Result testMultiWordArg(@CliArgument(name = "arg1")
+ String arg1, @CliArgument(name = "arg2")
+ String arg2) {
+ return null;
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/AuthorizeOperationForMBeansIntegrationTest.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/AuthorizeOperationForMBeansIntegrationTest.java
index 0000000,d63947b..c3f1658
mode 000000,100644..100644
--- a/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/AuthorizeOperationForMBeansIntegrationTest.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/AuthorizeOperationForMBeansIntegrationTest.java
@@@ -1,0 -1,323 +1,325 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import static org.junit.Assert.*;
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import java.io.Serializable;
+ import java.security.Principal;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Properties;
+
+ import javax.management.JMX;
+ import javax.management.MBeanServerConnection;
+ import javax.management.ObjectName;
+ import javax.management.remote.JMXConnector;
+ import javax.management.remote.JMXConnectorFactory;
+ import javax.management.remote.JMXServiceURL;
+
+ import org.junit.After;
+ import org.junit.Before;
+ import org.junit.Rule;
+ import org.junit.Test;
+ import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+ import org.junit.experimental.categories.Category;
+ import org.junit.rules.TestName;
+
+ import com.gemstone.gemfire.LogWriter;
+ import com.gemstone.gemfire.cache.Cache;
+ import com.gemstone.gemfire.cache.CacheFactory;
+ import com.gemstone.gemfire.cache.operations.OperationContext;
+ import com.gemstone.gemfire.distributed.DistributedMember;
+ import com.gemstone.gemfire.distributed.DistributedSystem;
+ import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+ import com.gemstone.gemfire.internal.AvailablePort;
+ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+ import com.gemstone.gemfire.management.DistributedSystemMXBean;
+ import com.gemstone.gemfire.management.MemberMXBean;
+ import com.gemstone.gemfire.management.internal.MBeanJMXAdapter;
+ import com.gemstone.gemfire.management.internal.security.ResourceOperationContext.ResourceOperationCode;
+ import com.gemstone.gemfire.security.AccessControl;
+ import com.gemstone.gemfire.security.AuthenticationFailedException;
+ import com.gemstone.gemfire.security.Authenticator;
+ import com.gemstone.gemfire.security.NotAuthorizedException;
+ import com.gemstone.gemfire.test.junit.categories.IntegrationTest;
+
+ /**
+ * Tests <code>JSONAuthorization.authorizeOperation(...)</code> with GemFire MBeans.
+ */
+ @Category(IntegrationTest.class)
+ @SuppressWarnings("deprecation")
+ public class AuthorizeOperationForMBeansIntegrationTest {
+
+ private GemFireCacheImpl cache;
+ private DistributedSystem ds;
+ private int jmxManagerPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+ private JMXConnector jmxConnector;
+ private MBeanServerConnection mbeanServer;
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Before
+ public void setUp() throws Exception {
+ System.setProperty("resource-auth-accessor", TestAccessControl.class.getName());
+ System.setProperty("resource-authenticator", TestAuthenticator.class.getName());
+
+ Properties properties = new Properties();
+ properties.put("name", this.testName.getMethodName());
+ properties.put(DistributionConfig.LOCATORS_NAME, "");
+ properties.put(DistributionConfig.MCAST_PORT_NAME, "0");
+ properties.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ properties.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ properties.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(this.jmxManagerPort));
+ properties.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+
+ this.ds = DistributedSystem.connect(properties);
+ this.cache = (GemFireCacheImpl) CacheFactory.create(ds);
+
+ this.jmxConnector = getGemfireMBeanServer(this.jmxManagerPort, "tushark", "tushark");
+ this.mbeanServer = this.jmxConnector.getMBeanServerConnection();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (this.jmxConnector != null) {
+ this.jmxConnector.close();
+ this.jmxConnector = null;
+ }
+ if (this.cache != null) {
+ this.cache.close();
+ this.cache = null;
+ }
+ if (this.ds != null) {
+ this.ds.disconnect();
+ this.ds = null;
+ }
+ }
+
+ /**
+ * This is testing a sampling of operations for DistributedSystemMXBean and AccessControlMXBean
+ */
+ @Test
+ public void operationsShouldBeCoveredByAuthorization() throws Exception {
+ ObjectName objectName = MBeanJMXAdapter.getDistributedSystemName();
+
+ checkListCacheServerObjectNames(objectName);
+ checkAlertLevel(objectName);
+ checkAccessControlMXBean();
+ checkBackUpMembers(objectName);
+ checkShutDownAllMembers(objectName);
+ checkCLIContext(this.mbeanServer);
+ }
+
+ private void checkListCacheServerObjectNames(final ObjectName objectName) throws Exception {
+ Object cacheServerObjectNames = this.mbeanServer.invoke(objectName, "listCacheServerObjectNames", null, null);
+ assertThat(cacheServerObjectNames).isNotNull().isInstanceOf(ObjectName[].class);
+ assertThat((ObjectName[])cacheServerObjectNames).hasSize(0); // this isn't really testing much since there are no CacheServers
+ }
+
+ private void checkAlertLevel(final ObjectName objectName) throws Exception {
+ // attribute AlertLevel
+ String oldLevel = (String) this.mbeanServer.getAttribute(objectName, "AlertLevel");
+ assertThat(oldLevel).isEqualTo("severe");
+
+ // operation changeAlertLevel
+ this.mbeanServer.invoke(
+ objectName,
+ "changeAlertLevel",
+ new Object[] { "warning" },
+ new String[] { String.class.getName() }
+ );
+ String newLevel = (String) this.mbeanServer.getAttribute(objectName, "AlertLevel");
+ assertThat(newLevel).isEqualTo("warning");
+ }
+
+ private void checkAccessControlMXBean() throws Exception {
+ final ResourceOperationCode resourceOperationCodes[] = {
- ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.LOCATE_ENTRY_REGION
++ ResourceOperationCode.LIST_DS,
++// FIXME: what should this be?
++// ResourceOperationCode.READ_DS,
++ ResourceOperationCode.CHANGE_ALERT_LEVEL,
++ ResourceOperationCode.LOCATE_ENTRY
+ };
+
+ ObjectName objectName = new ObjectName(ManagementInterceptor.OBJECT_NAME_ACCESSCONTROL);
+ for (ResourceOperationCode resourceOperationCode : resourceOperationCodes) {
+ boolean isAuthorizedForOperation = (Boolean) this.mbeanServer.invoke(
+ objectName,
+ "authorize",
+ new Object[] { resourceOperationCode.toString() },
+ new String[] { String.class.getName() }
+ );
+ assertThat(isAuthorizedForOperation).isTrue();
+ }
+
+ boolean isAuthorizedForAllOperations = (Boolean) mbeanServer.invoke(
+ objectName,
+ "authorize",
- new Object[] { ResourceOperationCode.ADMIN_DS.toString() },
++ new Object[] { ResourceOperationCode.ADMIN.toString() },
+ new String[] { String.class.getName() }
+ );
+ assertThat(isAuthorizedForAllOperations).isFalse();
+ }
+
+ private void checkBackUpMembers(final ObjectName objectName) throws Exception {
+ try {
+ this.mbeanServer.invoke(
+ objectName,
+ "backupAllMembers",
+ new Object[] { "targetPath", "baseLinePath" },
+ new String[] { String.class.getCanonicalName(), String.class.getCanonicalName() });
+ fail("Should not be authorized for backupAllMembers");
+ } catch (SecurityException expected) {
+ // expected
+ }
+ }
+
+ private void checkShutDownAllMembers(final ObjectName objectName) throws Exception {
+ try {
+ this.mbeanServer.invoke(
+ objectName,
+ "shutDownAllMembers",
+ null,
+ null
+ );
+ fail("Should not be authorized for shutDownAllMembers");
+ } catch (SecurityException expected) {
+ // expected
+ }
+ }
+
+ private void checkCLIContext(MBeanServerConnection mbeanServer) {
+ ObjectName objectName = MBeanJMXAdapter.getDistributedSystemName();
+ DistributedSystemMXBean proxy = JMX.newMXBeanProxy(mbeanServer, objectName, DistributedSystemMXBean.class);
+ ObjectName managerMemberObjectName = proxy.getMemberObjectName();
+ MemberMXBean memberMXBeanProxy = JMX.newMXBeanProxy(mbeanServer, managerMemberObjectName, MemberMXBean.class);
+
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("APP", "GFSH");
+ String result = memberMXBeanProxy.processCommand("locate entry --key=k1 --region=/region1", map);
+
+ assertThat(result).isNotNull().doesNotContain(SecurityException.class.getSimpleName());
+ }
+
+ private JMXConnector getGemfireMBeanServer(final int port, final String user, final String pwd) throws Exception {
+ JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:" + port + "/jmxrmi");
+ if (user != null) { // TODO: why isn't this deterministic? need to create 2nd test without a user?
+ Map<String, String[]> env = new HashMap<String, String[]>();
+ String[] creds = { user, pwd };
+ env.put(JMXConnector.CREDENTIALS, creds);
+ JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
+ return jmxc;
+ } else {
+ JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
+ return jmxc;
+ }
+ }
+
+ /**
+ * Fake Principal for testing.
+ */
+ @SuppressWarnings("serial")
+ public static class TestUsernamePrincipal implements Principal, Serializable {
+
+ private final String userName;
+
+ public TestUsernamePrincipal(final String userName) {
+ this.userName = userName;
+ }
+
+ @Override
+ public String getName() {
+ return this.userName;
+ }
+
+ @Override
+ public String toString() {
+ return this.userName;
+ }
+ }
+
+ /**
+ * Fake Authenticator for testing.
+ */
+ public static class TestAuthenticator implements Authenticator {
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void init(final Properties securityProps, final LogWriter systemLogger, final LogWriter securityLogger) throws AuthenticationFailedException {
+ }
+
+ @Override
+ public Principal authenticate(final Properties props, final DistributedMember member) throws AuthenticationFailedException {
+ String user = props.getProperty(ManagementInterceptor.USER_NAME);
+ String pwd = props.getProperty(ManagementInterceptor.PASSWORD);
+ if (user != null && !user.equals(pwd) && !"".equals(user)) {
+ throw new AuthenticationFailedException("Wrong username/password");
+ }
+ return new TestUsernamePrincipal(user);
+ }
+ }
+
+ /**
+ * Fake AccessControl for testing.
+ */
+ public static class TestAccessControl implements AccessControl {
+
+ private Principal principal;
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public void init(final Principal principal, final DistributedMember remoteMember, final Cache cache) throws NotAuthorizedException {
+ this.principal = principal;
+ }
+
+ @Override
+ public boolean authorizeOperation(String regionName, OperationContext context) {
+ if (principal.getName().equals("tushark")) {
+ ResourceOperationCode authorizedOps[] = {
+ ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.LOCATE_ENTRY_REGION
++// FOXME: Is this necessary?
++// ResourceOperationCode.READ_DS,
++ ResourceOperationCode.CHANGE_ALERT_LEVEL,
++ ResourceOperationCode.LOCATE_ENTRY
+ };
+
+ ResourceOperationContext ctx = (ResourceOperationContext) context;
+ boolean found = false;
+ for (ResourceOperationCode code : authorizedOps) {
+ if (ctx.getResourceOperationCode().equals(code)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+ return false;
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDataCommandsIntegrationTest.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDataCommandsIntegrationTest.java
index 0000000,b8c1c9d..bda4642
mode 000000,100755..100755
--- a/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDataCommandsIntegrationTest.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDataCommandsIntegrationTest.java
@@@ -1,0 -1,101 +1,101 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import java.io.IOException;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Properties;
+
+ import org.junit.After;
+ import org.junit.Before;
+ import org.junit.Rule;
+ import org.junit.Test;
+ import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+ import org.junit.experimental.categories.Category;
+ import org.junit.rules.TestName;
+
+ import com.gemstone.gemfire.cache.CacheFactory;
+ import com.gemstone.gemfire.distributed.DistributedSystem;
+ import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+ import com.gemstone.gemfire.management.internal.security.ResourceOperationContext.ResourceOperationCode;
+ import com.gemstone.gemfire.management.internal.security.AuthorizeOperationForMBeansIntegrationTest.TestAccessControl;
+ import com.gemstone.gemfire.management.internal.security.AuthorizeOperationForMBeansIntegrationTest.TestAuthenticator;
+ import com.gemstone.gemfire.test.junit.categories.IntegrationTest;
+
+ /**
+ * Tests operation codes for data commands.
+ */
+ @Category(IntegrationTest.class)
+ @SuppressWarnings("deprecation")
+ public class OperationCodesForDataCommandsIntegrationTest {
+
+ private GemFireCacheImpl cache;
+ private DistributedSystem ds;
+ private Map<String, ResourceOperationCode> commands = new HashMap<String, ResourceOperationCode>();
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Before
+ public void setUp() {
+ System.setProperty("resource-auth-accessor", TestAccessControl.class.getName());
+ System.setProperty("resource-authenticator", TestAuthenticator.class.getName());
+
+ Properties properties = new Properties();
+ properties.put("name", testName.getMethodName());
+ properties.put(DistributionConfig.LOCATORS_NAME, "");
+ properties.put(DistributionConfig.MCAST_PORT_NAME, "0");
+ properties.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+
+ this.ds = DistributedSystem.connect(properties);
+ this.cache = (GemFireCacheImpl) CacheFactory.create(ds);
+
- this.commands.put("put --key=k1 --value=v1 --region=/region1", ResourceOperationCode.PUT_REGION);
- this.commands.put("locate entry --key=k1 --region=/region1", ResourceOperationCode.LOCATE_ENTRY_REGION);
- this.commands.put("query --query=\"select * from /region1\"", ResourceOperationCode.QUERYDATA_DS);
- this.commands.put("export data --region=value --file=value --member=value", ResourceOperationCode.EXPORT_DATA_REGION);
- this.commands.put("import data --region=value --file=value --member=value", ResourceOperationCode.IMPORT_DATA_REGION);
- this.commands.put("rebalance", ResourceOperationCode.REBALANCE_DS);
++ this.commands.put("put --key=k1 --value=v1 --region=/region1", ResourceOperationCode.PUT);
++ this.commands.put("locate entry --key=k1 --region=/region1", ResourceOperationCode.LOCATE_ENTRY);
++ this.commands.put("query --query=\"select * from /region1\"", ResourceOperationCode.QUERY);
++ this.commands.put("export data --region=value --file=value --member=value", ResourceOperationCode.EXPORT_DATA);
++ this.commands.put("import data --region=value --file=value --member=value", ResourceOperationCode.IMPORT_DATA);
++ this.commands.put("rebalance", ResourceOperationCode.REBALANCE);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ if (this.cache != null) {
+ this.cache.close();
+ this.cache = null;
+ }
+ if (this.ds != null) {
+ this.ds.disconnect();
+ this.ds = null;
+ }
+ }
+
+ @Test
+ public void commandsShouldMapToCorrectResourceCodes() throws Exception {
+ for (String command : this.commands.keySet()) {
+ CLIOperationContext ctx = new CLIOperationContext(command);
+ assertThat(ctx.getResourceOperationCode()).isEqualTo(this.commands.get(command));
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDistributedSystemMXBeanTest.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDistributedSystemMXBeanTest.java
index 0000000,8b7edbf..65fcf56
mode 000000,100755..100755
--- a/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDistributedSystemMXBeanTest.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/management/internal/security/OperationCodesForDistributedSystemMXBeanTest.java
@@@ -1,0 -1,76 +1,76 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import static org.assertj.core.api.Assertions.assertThat;
+
+ import javax.management.ObjectName;
+
+ import org.junit.Test;
+ import org.junit.experimental.categories.Category;
+
+ import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode;
+ import com.gemstone.gemfire.management.internal.MBeanJMXAdapter;
+ import com.gemstone.gemfire.management.internal.security.ResourceOperationContext.ResourceOperationCode;
+ import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+ /**
+ * Tests operation codes for DistributedSystemMXBean operations.
+ */
+ @Category(UnitTest.class)
+ public class OperationCodesForDistributedSystemMXBeanTest {
+
+ private final String[] distributedSystemMXBeanOperations = {
+ "listCacheServerObjectNames",
+ "viewRemoteClusterStatus",
+ "getTotalHeapSize",
+ "setQueryCollectionsDepth",
+ "getQueryCollectionsDepth",
+ "changeAlertLevel",
+ "backupAllMembers",
+ "revokeMissingDiskStores",
+ "shutDownAllMembers",
+ "queryData",
+ "queryDataForCompressedResult",
+ "setQueryResultSetLimit"
+ };
+
+ private final ResourceOperationCode[] distributedSystemResourceOperationCodes = {
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.BACKUP_DS,
- ResourceOperationCode.REMOVE_DISKSTORE_DS,
- ResourceOperationCode.SHUTDOWN_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.QUERYDATA_DS
++ ResourceOperationCode.GET,
++ ResourceOperationCode.QUERY,
++ ResourceOperationCode.GET,
++ ResourceOperationCode.CHANGE_ALERT_LEVEL,
++ ResourceOperationCode.BACKUP_MEMBERS,
++ ResourceOperationCode.REVOKE_MISSING_DISKSTORE,
++ ResourceOperationCode.SHUTDOWN,
++ ResourceOperationCode.QUERY,
++ ResourceOperationCode.QUERY,
++ ResourceOperationCode.QUERY
+ };
+
+ @Test
+ public void operationsShouldMapToCodes() {
+ ObjectName objectName = MBeanJMXAdapter.getDistributedSystemName();
+ for (int i = 0; i < distributedSystemMXBeanOperations.length; i++) {
+ JMXOperationContext context = new JMXOperationContext(objectName, distributedSystemMXBeanOperations[i]);
+ assertThat(context.getResourceOperationCode()).isEqualTo(distributedSystemResourceOperationCodes[i]);
+ assertThat(context.getOperationCode()).isEqualTo(OperationCode.RESOURCE);
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
----------------------------------------------------------------------
diff --cc geode-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
index 0000000,0406831..2145445
mode 000000,100644..100644
--- a/geode-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
@@@ -1,0 -1,110 +1,120 @@@
+ /*
+ * 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 com.gemstone.gemfire.rest.internal.web.controllers;
+
+ import java.net.URI;
+ import java.text.SimpleDateFormat;
+ import java.util.ArrayList;
+ import java.util.List;
++
+ import org.springframework.http.converter.ByteArrayHttpMessageConverter;
+ import org.springframework.http.converter.HttpMessageConverter;
+ import org.springframework.http.converter.ResourceHttpMessageConverter;
+ import org.springframework.http.converter.StringHttpMessageConverter;
+ import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
+ import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
++import org.springframework.util.StringUtils;
+ import org.springframework.web.client.RestTemplate;
+ import org.springframework.web.util.UriComponentsBuilder;
+
+
+ /**
+ * The RestTestUtils class contains core functionality for Spring REST Template
+ * <p/>
+ *
+ * @author Nilkanth Patel
+ * @see org.springframework.context.ApplicationContext
+ * @see org.springframework.data.gemfire.GemfireTemplate
+ * @since 8.0
+ */
+ public class RestTestUtils {
+
+ public static final String BASE_URL = "http://localhost:8080";
+ public static final String GEMFIRE_REST_API_CONTEXT = "/gemfire-api";
+ public static final String GEMFIRE_REST_API_VERSION = "/v1";
+
+ public static final URI GEMFIRE_REST_API_WEB_SERVICE_URL = URI
+ .create(BASE_URL + GEMFIRE_REST_API_CONTEXT + GEMFIRE_REST_API_VERSION);
+
+ private static RestTemplate restTemplate;
+
+ public static RestTemplate getRestTemplate() {
+ if (restTemplate == null) {
+ restTemplate = new RestTemplate();
+
+ final List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
+
+ messageConverters.add(new ByteArrayHttpMessageConverter());
+ messageConverters.add(new ResourceHttpMessageConverter());
+ messageConverters.add(new StringHttpMessageConverter());
+ messageConverters.add(createMappingJackson2HttpMessageConverter());
+
+ restTemplate.setMessageConverters(messageConverters);
+ }
+ return restTemplate;
+ }
+
+ public static HttpMessageConverter<Object> createMappingJackson2HttpMessageConverter() {
+ final Jackson2ObjectMapperFactoryBean objectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
+
+ objectMapperFactoryBean.setFailOnEmptyBeans(true);
+ objectMapperFactoryBean.setIndentOutput(true);
+ objectMapperFactoryBean.setDateFormat(new SimpleDateFormat("MM/dd/yyyy"));
+ objectMapperFactoryBean
+ .setFeaturesToDisable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+ objectMapperFactoryBean
+ .setFeaturesToEnable(
+ com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_COMMENTS,
+ com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_SINGLE_QUOTES,
+ com.fasterxml.jackson.databind.DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
+ objectMapperFactoryBean.afterPropertiesSet();
+
+ final MappingJackson2HttpMessageConverter httpMessageConverter = new MappingJackson2HttpMessageConverter();
+ httpMessageConverter.setObjectMapper(objectMapperFactoryBean.getObject());
+ return httpMessageConverter;
+ }
+
+ /*
+ protected static HttpMessageConverter<Object> createMarshallingHttpMessageConverter() {
+ final Jaxb2Marshaller jaxbMarshaller = new Jaxb2Marshaller();
+
+ jaxbMarshaller.setContextPaths("com.gemstone.gemfire.web.rest.domain",
+ "com.gemstone.gemfire.web.controllers.support");
+ jaxbMarshaller.setMarshallerProperties(Collections.singletonMap(
+ "jaxb.formatted.output", Boolean.TRUE));
+
+ return new MarshallingHttpMessageConverter(jaxbMarshaller);
+ }
+ */
+
+ public static URI toUri(final String... pathSegments) {
+ return toUri(GEMFIRE_REST_API_WEB_SERVICE_URL, pathSegments);
+ }
+
+ public static URI toUri(final URI baseUrl, final String... pathSegments) {
+ return UriComponentsBuilder.fromUri(baseUrl).pathSegment(pathSegments)
+ .build().toUri();
+ }
++
++ public static String createRestURL(String baseURL, Object requestPart) {
++ if(StringUtils.isEmpty(requestPart)) {
++ return baseURL + RestTestUtils.GEMFIRE_REST_API_CONTEXT + RestTestUtils.GEMFIRE_REST_API_VERSION;
++ }else {
++ return baseURL + RestTestUtils.GEMFIRE_REST_API_CONTEXT + RestTestUtils.GEMFIRE_REST_API_VERSION + requestPart;
++ }
++ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-cq/src/test/java/com/gemstone/gemfire/security/ClientCQPostAuthorizationDUnitTest.java
----------------------------------------------------------------------
diff --cc geode-cq/src/test/java/com/gemstone/gemfire/security/ClientCQPostAuthorizationDUnitTest.java
index 0000000,0cb125f..bdb12cc
mode 000000,100644..100644
--- a/geode-cq/src/test/java/com/gemstone/gemfire/security/ClientCQPostAuthorizationDUnitTest.java
+++ b/geode-cq/src/test/java/com/gemstone/gemfire/security/ClientCQPostAuthorizationDUnitTest.java
@@@ -1,0 -1,511 +1,514 @@@
+ /*
+ * 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 com.gemstone.gemfire.security;
+
+ import java.util.Collection;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Properties;
+ import java.util.Random;
+
+ import security.AuthzCredentialGenerator;
+ import security.CredentialGenerator;
+
+ import com.gemstone.gemfire.cache.Region;
+ import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode;
+ import com.gemstone.gemfire.cache.query.CqAttributes;
+ import com.gemstone.gemfire.cache.query.CqAttributesFactory;
+ import com.gemstone.gemfire.cache.query.CqException;
+ import com.gemstone.gemfire.cache.query.CqListener;
+ import com.gemstone.gemfire.cache.query.CqQuery;
+ import com.gemstone.gemfire.cache.query.QueryService;
+ import com.gemstone.gemfire.cache.query.SelectResults;
+ import com.gemstone.gemfire.cache.query.cq.dunit.CqQueryTestListener;
+ import com.gemstone.gemfire.cache.query.internal.cq.ClientCQImpl;
+ import com.gemstone.gemfire.cache.query.internal.cq.CqService;
+ import com.gemstone.gemfire.cache.query.internal.cq.InternalCqQuery;
+ import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+ import com.gemstone.gemfire.internal.AvailablePort;
+ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+ import com.gemstone.gemfire.internal.logging.InternalLogWriter;
+ import com.gemstone.gemfire.test.dunit.Host;
+ import com.gemstone.gemfire.test.dunit.Invoke;
+ import com.gemstone.gemfire.test.dunit.LogWriterUtils;
+ import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+ import com.gemstone.gemfire.test.dunit.Wait;
+ import com.gemstone.gemfire.test.dunit.WaitCriterion;
++
++import static java.rmi.activation.ActivationGroup.getSystem;
++
+ /**
+ * This is for multiuser-authentication
+ *
+ * @author ashetkar
+ *
+ */
+ public class ClientCQPostAuthorizationDUnitTest extends
+ ClientAuthorizationTestBase {
+
+ // public static final String regionName = "ClientCQPostAuthorizationDUnitTest_region";
+
+ public static final Map<String, String> cqNameToQueryStrings = new HashMap<String, String>();
+
+ static {
+ cqNameToQueryStrings.put("CQ_0", "SELECT * FROM ");
+ cqNameToQueryStrings.put("CQ_1", "SELECT * FROM ");
+ }
+
+ public ClientCQPostAuthorizationDUnitTest(String name) {
+ super(name);
+ }
+
+ public void setUp() throws Exception {
+
+ super.setUp();
+ getSystem();
+ Invoke.invokeInEveryVM(new SerializableRunnable("getSystem") {
+ public void run() {
+ getSystem();
+ }
+ });
+
+ final Host host = Host.getHost(0);
+ server1 = host.getVM(0);
+ server2 = host.getVM(1);
+ client1 = host.getVM(2);
+ client2 = host.getVM(3);
+
+ server1.invoke(() -> SecurityTestUtil.registerExpectedExceptions( serverExpectedExceptions ));
+ server2.invoke(() -> SecurityTestUtil.registerExpectedExceptions( serverExpectedExceptions ));
+ client2.invoke(() -> SecurityTestUtil.registerExpectedExceptions( clientExpectedExceptions ));
+ SecurityTestUtil.registerExpectedExceptions(clientExpectedExceptions);
+ }
+
+ @Override
+ protected final void preTearDown() throws Exception {
+ client1.invoke(() -> SecurityTestUtil.closeCache());
+ client2.invoke(() -> SecurityTestUtil.closeCache());
+ server1.invoke(() -> SecurityTestUtil.closeCache());
+ server2.invoke(() -> SecurityTestUtil.closeCache());
+ }
+
+ public void testAllowCQForAllMultiusers() throws Exception {
+ /*
+ * Start a server
+ * Start a client1 with two users with valid credentials and post-authz'ed for CQ
+ * Each user registers a unique CQ
+ * Client2 does some operations on the region which satisfies both the CQs
+ * Validate that listeners for both the CQs are invoked.
+ */
+ doStartUp(Integer.valueOf(2), Integer.valueOf(5), new Boolean[] {true,
+ true});
+ }
+
+ public void testDisallowCQForAllMultiusers() throws Exception {
+ /*
+ * Start a server
+ * Start a client1 with two users with valid credentials but not post-authz'ed for CQ
+ * Each user registers a unique CQ
+ * Client2 does some operations on the region which satisfies both the CQs
+ * Validate that listeners for none of the CQs are invoked.
+ */
+ doStartUp(Integer.valueOf(2), Integer.valueOf(5), new Boolean[] {false,
+ false});
+ }
+
+ public void testDisallowCQForSomeMultiusers() throws Exception {
+ /*
+ * Start a server
+ * Start a client1 with two users with valid credentials
+ * User1 is post-authz'ed for CQ but user2 is not.
+ * Each user registers a unique CQ
+ * Client2 does some operations on the region which satisfies both the CQs
+ * Validate that listener for User1's CQ is invoked but that for User2's CQ is not invoked.
+ */
+ doStartUp(Integer.valueOf(2), Integer.valueOf(5), new Boolean[] {true,
+ false});
+ }
+
+ public void testAllowCQForAllMultiusersWithFailover() throws Exception {
+ /*
+ * Start a server1
+ * Start a client1 with two users with valid credentials and post-authz'ed for CQ
+ * Each user registers a unique CQ
+ * Client2 does some operations on the region which satisfies both the CQs
+ * Validate that listeners for both the CQs are invoked.
+ * Start server2 and shutdown server1
+ * Client2 does some operations on the region which satisfies both the CQs
+ * Validate that listeners for both the CQs are get updates.
+ */
+ doStartUp(Integer.valueOf(2), Integer.valueOf(5), new Boolean[] {true,
+ true}, Boolean.TRUE);
+ }
+
+ public void doStartUp(Integer numOfUsers, Integer numOfPuts,
+ Boolean[] postAuthzAllowed) throws Exception {
+ doStartUp(numOfUsers, numOfPuts, postAuthzAllowed, Boolean.FALSE /* failover */);
+ }
+
+ public void doStartUp(Integer numOfUsers, Integer numOfPuts,
+ Boolean[] postAuthzAllowed, Boolean failover) throws Exception {
+ AuthzCredentialGenerator gen = this.getXmlAuthzGenerator();
+ CredentialGenerator cGen = gen.getCredentialGenerator();
+ Properties extraAuthProps = cGen.getSystemProperties();
+ Properties javaProps = cGen.getJavaProperties();
+ Properties extraAuthzProps = gen.getSystemProperties();
+ String authenticator = cGen.getAuthenticator();
+ String accessor = gen.getAuthorizationCallback();
+ String authInit = cGen.getAuthInit();
+ TestAuthzCredentialGenerator tgen = new TestAuthzCredentialGenerator(gen);
+
+ Properties serverProps = buildProperties(authenticator, accessor, true,
+ extraAuthProps, extraAuthzProps);
+
+ Properties opCredentials;
+ cGen = tgen.getCredentialGenerator();
+ Properties javaProps2 = null;
+ if (cGen != null) {
+ javaProps2 = cGen.getJavaProperties();
+ }
+
+ int[] indices = new int[numOfPuts];
+ for (int index = 0; index < numOfPuts; ++index) {
+ indices[index] = index;
+ }
+
+ Random rnd = new Random();
+ Properties[] authProps = new Properties[numOfUsers];
+ for (int i = 0; i < numOfUsers; i++) {
+ int rand = rnd.nextInt(100) + 1;
+ if (postAuthzAllowed[i]) {
+ opCredentials = tgen.getAllowedCredentials(new OperationCode[] {
+ OperationCode.EXECUTE_CQ, OperationCode.GET}, // For callback, GET should be allowed
+ new String[] {regionName}, indices, rand);
+ // authProps[i] = gen.getAllowedCredentials(
+ // new OperationCode[] {OperationCode.EXECUTE_CQ},
+ // new String[] {regionName}, rnd.nextInt(100) + 1);
+ } else {
+ opCredentials = tgen.getDisallowedCredentials(new OperationCode[] {
+ OperationCode.GET}, // For callback, GET should be disallowed
+ new String[] {regionName}, indices, rand);
+ // authProps[i] = gen.getDisallowedCredentials(
+ // new OperationCode[] {OperationCode.EXECUTE_CQ},
+ // new String[] {regionName}, rnd.nextInt(100) + 1);
+ }
+ authProps[i] = SecurityTestUtil.concatProperties(new Properties[] {
+ opCredentials, extraAuthProps, extraAuthzProps});
+ }
+
+ // Get ports for the servers
+ Integer port1 = Integer.valueOf(AvailablePort
+ .getRandomAvailablePort(AvailablePort.SOCKET));
+ Integer port2 = Integer.valueOf(AvailablePort
+ .getRandomAvailablePort(AvailablePort.SOCKET));
+ Integer locatorPort = Integer.valueOf(AvailablePort
+ .getRandomAvailablePort(AvailablePort.SOCKET));
+ // Close down any running servers
+ server1.invoke(() -> SecurityTestUtil.closeCache());
+ server2.invoke(() -> SecurityTestUtil.closeCache());
+
+ server1.invoke(() -> ClientCQPostAuthorizationDUnitTest.createServerCache(serverProps, javaProps, locatorPort, port1));
+ client1.invoke(ClientCQPostAuthorizationDUnitTest.class,
+ "createClientCache", new Object[] {javaProps2, authInit, authProps,
+ new Integer[] {port1, port2}, numOfUsers, postAuthzAllowed});
+ client2.invoke(ClientCQPostAuthorizationDUnitTest.class,
+ "createClientCache", new Object[] {javaProps2, authInit, authProps,
+ new Integer[] {port1, port2}, numOfUsers, postAuthzAllowed});
+
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.createCQ(numOfUsers));
+ client1.invoke(ClientCQPostAuthorizationDUnitTest.class, "executeCQ",
+ new Object[] {numOfUsers, new Boolean[] {false, false}, numOfPuts,
+ new String[numOfUsers], postAuthzAllowed});
+
+ client2.invoke(() -> ClientCQPostAuthorizationDUnitTest.doPuts(numOfPuts, Boolean.TRUE/* put last key */));
+ if (!postAuthzAllowed[0]) {
+ // There is no point waiting as no user is authorized to receive cq events.
+ try {Thread.sleep(1000);} catch (InterruptedException ie) {}
+ } else {
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.waitForLastKey(Integer.valueOf(0)));
+ if (postAuthzAllowed[1]) {
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.waitForLastKey(Integer.valueOf(1)));
+ }
+ }
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.checkCQListeners(numOfUsers, postAuthzAllowed,
+ numOfPuts + 1/* last key */, 0, !failover));
+ if (failover) {
+ server2.invoke(() -> ClientCQPostAuthorizationDUnitTest.createServerCache(serverProps, javaProps, locatorPort, port2));
+ server1.invoke(() -> SecurityTestUtil.closeCache());
+
+ // Allow time for client1 to register its CQs on server2
+ server2.invoke(() -> ClientCQPostAuthorizationDUnitTest.allowCQsToRegister(Integer.valueOf(2)));
+
+ client2.invoke(() -> ClientCQPostAuthorizationDUnitTest.doPuts(numOfPuts, Boolean.TRUE/* put last key */));
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.waitForLastKeyUpdate(Integer.valueOf(0)));
+ client1.invoke(() -> ClientCQPostAuthorizationDUnitTest.checkCQListeners(numOfUsers, postAuthzAllowed,
+ numOfPuts + 1/* last key */, numOfPuts + 1/* last key */,
+ Boolean.TRUE));
+ }
+ }
+
+ public static void createServerCache(Properties serverProps,
+ Properties javaProps, Integer serverPort) {
+ Integer locatorPort = Integer.valueOf(AvailablePort
+ .getRandomAvailablePort(AvailablePort.SOCKET));
+ SecurityTestUtil.createCacheServer((Properties)serverProps, javaProps,
+ locatorPort, null, serverPort, Boolean.TRUE, Integer.valueOf(
+ SecurityTestUtil.NO_EXCEPTION));
+ }
+
+ public static void createServerCache(Properties serverProps,
+ Properties javaProps, Integer locatorPort, Integer serverPort) {
+ SecurityTestUtil.createCacheServer((Properties)serverProps, javaProps,
+ locatorPort, null, serverPort, Boolean.TRUE, Integer.valueOf(
+ SecurityTestUtil.NO_EXCEPTION));
+ }
+
+ public static void createClientCache(Properties javaProps, String authInit,
+ Properties[] authProps, Integer ports[], Integer numOfUsers,
+ Boolean[] postAuthzAllowed) {
+ SecurityTestUtil.createCacheClientForMultiUserMode(numOfUsers, authInit,
+ authProps, javaProps, ports, null, Boolean.FALSE,
+ SecurityTestUtil.NO_EXCEPTION);
+ }
+
+ public static void createCQ(Integer num) {
+ for (int i = 0; i < num; i++) {
+ QueryService cqService = SecurityTestUtil.proxyCaches[i].getQueryService();
+ String cqName = "CQ_" + i;
+ String queryStr = cqNameToQueryStrings.get(cqName)
+ + SecurityTestUtil.proxyCaches[i].getRegion(regionName).getFullPath();
+ // Create CQ Attributes.
+ CqAttributesFactory cqf = new CqAttributesFactory();
+ CqListener[] cqListeners = {new CqQueryTestListener(LogWriterUtils.getLogWriter())};
+ ((CqQueryTestListener)cqListeners[0]).cqName = cqName;
+
+ cqf.initCqListeners(cqListeners);
+ CqAttributes cqa = cqf.create();
+
+ // Create CQ.
+ try {
+ CqQuery cq1 = cqService.newCq(cqName, queryStr, cqa);
+ assertTrue("newCq() state mismatch", cq1.getState().isStopped());
+ } catch (Exception ex) {
+ AssertionError err = new AssertionError("Failed to create CQ " + cqName
+ + " . ");
+ err.initCause(ex);
+ LogWriterUtils.getLogWriter().info("CqService is :" + cqService, err);
+ throw err;
+ }
+ }
+ }
+
+ public static void executeCQ(Integer num, Boolean[] initialResults,
+ Integer expectedResultsSize, String[] expectedErr, Boolean[] postAuthzAllowed) {
+ InternalLogWriter logWriter = InternalDistributedSystem.getStaticInternalLogWriter();
+ for (int i = 0; i < num; i++) {
+ try {
+ if (expectedErr[i] != null) {
+ logWriter.info(
+ "<ExpectedException action=add>" + expectedErr[i]
+ + "</ExpectedException>");
+ }
+ CqQuery cq1 = null;
+ String cqName = "CQ_" + i;
+ String queryStr = cqNameToQueryStrings.get(cqName)
+ + SecurityTestUtil.proxyCaches[i].getRegion(regionName)
+ .getFullPath();
+ QueryService cqService = SecurityTestUtil.proxyCaches[i]
+ .getQueryService();
+
+ // Get CqQuery object.
+ try {
+ cq1 = cqService.getCq(cqName);
+ if (cq1 == null) {
+ LogWriterUtils.getLogWriter().info(
+ "Failed to get CqQuery object for CQ name: " + cqName);
+ fail("Failed to get CQ " + cqName);
+ } else {
+ LogWriterUtils.getLogWriter().info("Obtained CQ, CQ name: " + cq1.getName());
+ assertTrue("newCq() state mismatch", cq1.getState().isStopped());
+ }
+ } catch (Exception ex) {
+ LogWriterUtils.getLogWriter().info("CqService is :" + cqService);
+ LogWriterUtils.getLogWriter().error(ex);
+ AssertionError err = new AssertionError("Failed to execute CQ "
+ + cqName);
+ err.initCause(ex);
+ throw err;
+ }
+
+ if (initialResults[i]) {
+ SelectResults cqResults = null;
+
+ try {
+ cqResults = cq1.executeWithInitialResults();
+ } catch (CqException ce) {
+ if (ce.getCause() instanceof NotAuthorizedException && !postAuthzAllowed[i]) {
+ LogWriterUtils.getLogWriter().info("Got expected exception for CQ " + cqName);
+ } else {
+ LogWriterUtils.getLogWriter().info("CqService is: " + cqService);
+ ce.printStackTrace();
+ AssertionError err = new AssertionError("Failed to execute CQ "
+ + cqName);
+ err.initCause(ce);
+ throw err;
+ }
+ } catch (Exception ex) {
+ LogWriterUtils.getLogWriter().info("CqService is: " + cqService);
+ ex.printStackTrace();
+ AssertionError err = new AssertionError("Failed to execute CQ "
+ + cqName);
+ err.initCause(ex);
+ throw err;
+ }
+ LogWriterUtils.getLogWriter().info("initial result size = " + cqResults.size());
+ assertTrue("executeWithInitialResults() state mismatch", cq1
+ .getState().isRunning());
+ if (expectedResultsSize >= 0) {
+ assertEquals("unexpected results size", expectedResultsSize
+ .intValue(), cqResults.size());
+ }
+ } else {
+ try {
+ cq1.execute();
+ } catch (CqException ce) {
+ if (ce.getCause() instanceof NotAuthorizedException && !postAuthzAllowed[i]) {
+ LogWriterUtils.getLogWriter().info("Got expected exception for CQ " + cqName);
+ } else {
+ LogWriterUtils.getLogWriter().info("CqService is: " + cqService);
+ ce.printStackTrace();
+ AssertionError err = new AssertionError("Failed to execute CQ "
+ + cqName);
+ err.initCause(ce);
+ throw err;
+ }
+ } catch (Exception ex) {
+ AssertionError err = new AssertionError("Failed to execute CQ "
+ + cqName);
+ err.initCause(ex);
+ if (expectedErr == null) {
+ LogWriterUtils.getLogWriter().info("CqService is: " + cqService, err);
+ }
+ throw err;
+ }
+ assertTrue("execute() state mismatch", cq1.getState().isRunning() == postAuthzAllowed[i]);
+ }
+ } finally {
+ if (expectedErr[i] != null) {
+ logWriter.info(
+ "<ExpectedException action=remove>" + expectedErr[i]
+ + "</ExpectedException>");
+ }
+ }
+ }
+ }
+
+ public static void doPuts(Integer num, Boolean putLastKey) {
+ // Region region = GemFireCache.getInstance().getRegion(regionName);
+ Region region = SecurityTestUtil.proxyCaches[0].getRegion(regionName);
+ for (int i = 0; i < num; i++) {
+ region.put("CQ_key"+i, "CQ_value"+i);
+ }
+ if (putLastKey) {
+ region.put("LAST_KEY", "LAST_KEY");
+ }
+ }
+
+ public static void putLastKey() {
+ Region region = GemFireCacheImpl.getInstance().getRegion(regionName);
+ region.put("LAST_KEY", "LAST_KEY");
+ }
+
+ public static void waitForLastKey(Integer cqIndex) {
+ String cqName = "CQ_" + cqIndex;
+ QueryService qService = SecurityTestUtil.proxyCaches[cqIndex].getQueryService();
+ ClientCQImpl cqQuery = (ClientCQImpl)qService.getCq(cqName);
+ ((CqQueryTestListener)cqQuery.getCqListeners()[0])
+ .waitForCreated("LAST_KEY");
+ // WaitCriterion wc = new WaitCriterion() {
+ // public boolean done() {
+ // Region region = GemFireCache.getInstance().getRegion(regionName);
+ // Region.Entry entry = region.getEntry("LAST_KEY");
+ // if (entry != null && entry.getValue() != null) {
+ // return false;
+ // } else if (entry.getValue() != null) {
+ // return true;
+ // }
+ // return false;
+ // }
+ // public String description() {
+ // return "Last key not received.";
+ // }
+ // };
+ // DistributedTestCase.waitForCriterion(wc, 60 * 1000, 100, false);
+ }
+
+ public static void waitForLastKeyUpdate(Integer cqIndex) {
+ String cqName = "CQ_" + cqIndex;
+ QueryService qService = SecurityTestUtil.proxyCaches[cqIndex].getQueryService();
+ ClientCQImpl cqQuery = (ClientCQImpl)qService.getCq(cqName);
+ ((CqQueryTestListener)cqQuery.getCqListeners()[0])
+ .waitForUpdated("LAST_KEY");
+ }
+
+ public static void allowCQsToRegister(Integer number) {
+ final int num = number;
+ WaitCriterion wc = new WaitCriterion() {
+ public boolean done() {
+ CqService cqService = GemFireCacheImpl.getInstance().getCqService();
+ cqService.start();
+ Collection<? extends InternalCqQuery> cqs = cqService.getAllCqs();
+ if (cqs != null) {
+ return cqs.size() >= num;
+ } else {
+ return false;
+ }
+ }
+
+ public String description() {
+ return num + "Waited for " + num
+ + " CQs to be registered on this server.";
+ }
+ };
+ Wait.waitForCriterion(wc, 60 * 1000, 100, false);
+ }
+
+ public static void checkCQListeners(Integer numOfUsers,
+ Boolean[] expectedListenerInvocation, Integer createEventsSize,
+ Integer updateEventsSize, Boolean closeCache) {
+ for (int i = 0; i < numOfUsers; i++) {
+ String cqName = "CQ_" + i;
+ QueryService qService = SecurityTestUtil.proxyCaches[i].getQueryService();
+ ClientCQImpl cqQuery = (ClientCQImpl)qService.getCq(cqName);
+ if (expectedListenerInvocation[i]) {
+ for (CqListener listener : cqQuery.getCqListeners()) {
+ assertEquals(createEventsSize.intValue(),
+ ((CqQueryTestListener)listener).getCreateEventCount());
+ assertEquals(updateEventsSize.intValue(),
+ ((CqQueryTestListener)listener).getUpdateEventCount());
+ }
+ } else {
+ for (CqListener listener : cqQuery.getCqListeners()) {
+ assertEquals(0, ((CqQueryTestListener)listener).getTotalEventCount());
+ }
+ }
+ if (closeCache) {
+ SecurityTestUtil.proxyCaches[i].close();
+ }
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java
----------------------------------------------------------------------
diff --cc geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java
index 0000000,f24b136..48aee7b
mode 000000,100644..100644
--- a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java
+++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java
@@@ -1,0 -1,240 +1,242 @@@
+ /*
+ * 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 com.gemstone.gemfire.cache.lucene.internal.distributed;
+
+ import java.io.Serializable;
+ import java.util.HashMap;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.concurrent.CancellationException;
+
+ import org.junit.Assert;
+ import org.junit.experimental.categories.Category;
+
+ import com.gemstone.gemfire.cache.Cache;
+ import com.gemstone.gemfire.cache.EvictionAction;
+ import com.gemstone.gemfire.cache.EvictionAlgorithm;
+ import com.gemstone.gemfire.cache.Region;
+ import com.gemstone.gemfire.cache.RegionFactory;
+ import com.gemstone.gemfire.cache.RegionShortcut;
+ import com.gemstone.gemfire.cache.control.RebalanceOperation;
+ import com.gemstone.gemfire.cache.control.RebalanceResults;
+ import com.gemstone.gemfire.cache.lucene.LuceneQuery;
+ import com.gemstone.gemfire.cache.lucene.LuceneQueryResults;
+ import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
+ import com.gemstone.gemfire.cache.lucene.LuceneService;
+ import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider;
+ import com.gemstone.gemfire.cache.lucene.internal.LuceneServiceImpl;
+ import com.gemstone.gemfire.cache30.CacheTestCase;
+ import com.gemstone.gemfire.internal.cache.EvictionAttributesImpl;
+ import com.gemstone.gemfire.internal.cache.PartitionedRegion;
+ import com.gemstone.gemfire.test.dunit.Host;
+ import com.gemstone.gemfire.test.dunit.SerializableCallable;
+ import com.gemstone.gemfire.test.dunit.VM;
+ import com.gemstone.gemfire.test.junit.categories.DistributedTest;
+
++import static org.apache.logging.log4j.core.util.ExtensionLanguageMapping.VM;
++
+ @Category(DistributedTest.class)
+ public class LuceneFunctionReadPathDUnitTest extends CacheTestCase {
+ private static final String INDEX_NAME = "index";
+
+ private static final long serialVersionUID = 1L;
+
+ private VM server1;
+ private VM server2;
+
+ public LuceneFunctionReadPathDUnitTest(String name) {
+ super(name);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ Host host = Host.getHost(0);
+ server1 = host.getVM(0);
+ server2 = host.getVM(1);
+ }
+
+ public void testEnd2EndFunctionExecution() {
+ e2eTextSearchForRegionType(RegionShortcut.PARTITION);
+ e2eTextSearchForRegionType(RegionShortcut.PARTITION_PERSISTENT);
+ e2eTextSearchForRegionType(RegionShortcut.PARTITION_OVERFLOW);
+ e2eTextSearchForRegionType(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW);
+ }
+
+ private void e2eTextSearchForRegionType(RegionShortcut type) {
+ final String regionName = type.toString();
+ createPartitionRegionAndIndex(server1, regionName, type);
+ putDataInRegion(server1, regionName);
+ createPartitionRegionAndIndex(server2, regionName, type);
+ // Make sure we can search from both members
+ executeTextSearch(server1, regionName);
+ executeTextSearch(server2, regionName);
+
+ rebalanceRegion(server1);
+ // Make sure the search still works
+ executeTextSearch(server1, regionName);
+ executeTextSearch(server2, regionName);
+ destroyRegion(server2, regionName);
+ }
+
+ private void rebalanceRegion(VM vm) {
+ // Do a rebalance
+ vm.invoke(new SerializableCallable<Object>() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public Object call() throws CancellationException, InterruptedException {
+ RebalanceOperation op = getCache().getResourceManager().createRebalanceFactory().start();
+ RebalanceResults results = op.getResults();
+ assertTrue(1 < results.getTotalBucketTransfersCompleted());
+ return null;
+ }
+ });
+ }
+
+ private void executeTextSearch(VM vm, final String regionName) {
+ SerializableCallable<Object> executeSearch = new SerializableCallable<Object>("executeSearch") {
+ private static final long serialVersionUID = 1L;
+
+ public Object call() throws Exception {
+ Cache cache = getCache();
+ assertNotNull(cache);
+ Region<Object, Object> region = cache.getRegion(regionName);
+ Assert.assertNotNull(region);
+
+ LuceneService service = LuceneServiceProvider.get(cache);
+ LuceneQuery<Integer, TestObject> query;
+ query = service.createLuceneQueryFactory().create(INDEX_NAME, regionName, "text:world");
+ LuceneQueryResults<Integer, TestObject> results = query.search();
+ assertEquals(3, results.size());
+ List<LuceneResultStruct<Integer, TestObject>> page = results.getNextPage();
+
+ Map<Integer, TestObject> data = new HashMap<Integer, TestObject>();
+ for (LuceneResultStruct<Integer, TestObject> row : page) {
+ data.put(row.getKey(), row.getValue());
+ }
+
+ assertEquals(data, region);
+ return null;
+ }
+ };
+
+ vm.invoke(executeSearch);
+ }
+
+ private void putDataInRegion(VM vm, final String regionName) {
+ SerializableCallable<Object> createSomeData = new SerializableCallable<Object>("putDataInRegion") {
+ private static final long serialVersionUID = 1L;
+
+ public Object call() throws Exception {
+ final Cache cache = getCache();
+ Region<Object, Object> region = cache.getRegion(regionName);
+ assertNotNull(region);
+ region.put(1, new TestObject("hello world"));
+ region.put(113, new TestObject("hi world"));
+ region.put(2, new TestObject("goodbye world"));
+
+ return null;
+ }
+ };
+
+ vm.invoke(createSomeData);
+ }
+
+ private void createPartitionRegionAndIndex(VM vm, final String regionName, final RegionShortcut type) {
+ SerializableCallable<Object> createPartitionRegion = new SerializableCallable<Object>("createRegionAndIndex") {
+ private static final long serialVersionUID = 1L;
+
+ public Object call() throws Exception {
+ final Cache cache = getCache();
+ assertNotNull(cache);
+ LuceneService service = LuceneServiceProvider.get(cache);
+ service.createIndex(INDEX_NAME, regionName, "text");
+ RegionFactory<Object, Object> regionFactory = cache.createRegionFactory(type);
+ if (regionName.contains("OVERFLOW")) {
+ System.out.println("yello");
+ EvictionAttributesImpl evicAttr = new EvictionAttributesImpl().setAction(EvictionAction.OVERFLOW_TO_DISK);
+ evicAttr.setAlgorithm(EvictionAlgorithm.LRU_ENTRY).setMaximum(1);
+ regionFactory.setEvictionAttributes(evicAttr);
+ }
+ regionFactory.create(regionName);
+ return null;
+ }
+ };
+ vm.invoke(createPartitionRegion);
+ }
+
+ private void destroyRegion(VM vm, final String regionName) {
+ SerializableCallable<Object> createPartitionRegion = new SerializableCallable<Object>("destroyRegion") {
+ private static final long serialVersionUID = 1L;
+
+ public Object call() throws Exception {
+ final Cache cache = getCache();
+ assertNotNull(cache);
+ String aeqId = LuceneServiceImpl.getUniqueIndexName(INDEX_NAME, regionName);
+ PartitionedRegion chunkRegion = (PartitionedRegion) cache.getRegion(aeqId + ".chunks");
+ assertNotNull(chunkRegion);
+ chunkRegion.destroyRegion();
+ PartitionedRegion fileRegion = (PartitionedRegion) cache.getRegion(aeqId + ".files");
+ assertNotNull(fileRegion);
+ fileRegion.destroyRegion();
+ Region<Object, Object> region = cache.getRegion(regionName);
+ assertNotNull(region);
+ region.destroyRegion();
+ return null;
+ }
+ };
+ vm.invoke(createPartitionRegion);
+ }
+
+ private static class TestObject implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private String text;
+
+ public TestObject(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((text == null) ? 0 : text.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ TestObject other = (TestObject) obj;
+ if (text == null) {
+ if (other.text != null)
+ return false;
+ } else if (!text.equals(other.text))
+ return false;
+ return true;
+ }
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-web-api/build.gradle
----------------------------------------------------------------------
diff --cc geode-web-api/build.gradle
index 0000000,51848c2..d854d17
mode 000000,100755..100755
--- a/geode-web-api/build.gradle
+++ b/geode-web-api/build.gradle
@@@ -1,0 -1,55 +1,67 @@@
+ /*
+ * 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.
+ */
+
+ apply plugin: 'war'
+
+ dependencies {
+ compile 'commons-lang:commons-lang:' + project.'commons-lang.version'
+ compile 'commons-fileupload:commons-fileupload:' + project.'commons-fileupload.version'
+ compile 'com.fasterxml:classmate:' + project.'classmate.version'
+ compile 'com.fasterxml.jackson.core:jackson-annotations:' + project.'jackson.version'
+ compile 'com.fasterxml.jackson.core:jackson-core:' + project.'jackson.version'
+ compile 'com.fasterxml.jackson.core:jackson-databind:' + project.'jackson.version'
+ compile 'com.fasterxml.jackson.module:jackson-module-scala_2.10:' + project.'jackson-module-scala_2.10.version'
+ compile 'com.google.guava:guava:' + project.'guava.version'
+ compile 'com.mangofactory:swagger-springmvc:' + project.'swagger-springmvc.version'
+ compile 'com.thoughtworks.paranamer:paranamer:' + project.'paranamer.version'
+ compile 'com.wordnik:swagger-annotations:' + project.'swagger.version'
+ compile 'com.wordnik:swagger-core_2.10:' + project.'swagger.version'
+ compile 'org.json4s:json4s-ast_2.10:' + project.'json4s.version'
+ compile 'org.json4s:json4s-ext_2.10:' + project.'json4s.version'
+ compile 'org.json4s:json4s-core_2.10:' + project.'json4s.version'
+ compile 'org.json4s:json4s-jackson_2.10:' + project.'json4s.version'
+ compile 'org.json4s:json4s-native_2.10:' + project.'json4s.version'
+ compile 'org.scala-lang:scala-library:' + project.'scala.version'
+ compile 'org.scala-lang:scala-reflect:' + project.'scala.version'
+ compile 'org.springframework.hateoas:spring-hateoas:' + project.'spring-hateos.version'
+ compile 'org.springframework:spring-aspects:' + project.'springframework.version'
+ compile 'org.springframework:spring-oxm:' + project.'springframework.version'
+
+ provided 'javax.servlet:javax.servlet-api:' + project.'javax.servlet-api.version'
+ provided project(':geode-core')
+ }
+
+ jar {
+ from sourceSets.main.output
+ }
+
+ war {
+ classpath configurations.runtime
+ }
+
++test {
++ def assemblyPath = project(':gemfire-assembly').buildDir
++ def distributionBaseName = "apache-geode"
++ environment 'GEMFIRE', "$assemblyPath/install/${distributionBaseName}"
++}
++
++distributedTest {
++ def assemblyPath = project(':gemfire-assembly').buildDir
++ def distributionBaseName = "apache-geode"
++ environment 'GEMFIRE', "$assemblyPath/install/${distributionBaseName}"
++}
++