/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. You may obtain a * copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package org.apache.geode.management.internal.cli.commands; import org.apache.geode.cache.*; import org.apache.geode.management.DistributedRegionMXBean; import org.apache.geode.management.ManagementService; import org.apache.geode.management.ManagerMXBean; import org.apache.geode.management.cli.Result; import org.apache.geode.management.internal.cli.HeadlessGfsh; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.result.CompositeResultData; import org.apache.geode.management.internal.cli.result.ResultData; import org.apache.geode.management.internal.cli.util.CommandStringBuilder; import org.apache.geode.test.dunit.SerializableRunnable; import org.apache.geode.test.dunit.SerializableRunnableIF; import org.apache.geode.test.dunit.VM; import org.apache.geode.test.dunit.WaitCriterion; import org.apache.geode.test.junit.categories.DistributedTest; import org.junit.Test; import org.junit.experimental.categories.Category; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import java.util.Properties; import static org.apache.geode.distributed.ConfigurationProperties.*; import static org.apache.geode.test.dunit.Assert.*; import static org.apache.geode.test.dunit.Host.getHost; import static org.apache.geode.test.dunit.LogWriterUtils.getLogWriter; import static org.apache.geode.test.dunit.Wait.waitForCriterion; /** * The GetCommandOnRegionWithCacheLoaderDuringCacheMissDUnitTest class is test suite of test cases * testing the Gfsh 'get' data command when a cache miss occurs on data in a Region with a * CacheLoader defined. * * @see org.apache.geode.management.internal.cli.commands.CliCommandTestBase * @see org.apache.geode.management.internal.cli.commands.DataCommands * @since GemFire 8.0 */ @SuppressWarnings("unused") @Category(DistributedTest.class) public class GetCommandOnRegionWithCacheLoaderDuringCacheMissDUnitTest extends CliCommandTestBase { private static final String GEMFIRE_MANAGER_NAME = "GemManagerNode"; private static final String GEMFIRE_SERVER_NAME = "GemServerDataNode"; private static final String GEMFIRE_LOG_LEVEL = System.getProperty("logLevel", "config"); private static final String USERS_REGION_NAME = "Users"; @Override public final void postSetUpCliCommandTestBase() throws Exception { Properties managerDistributedSystemProperties = createDistributedSystemProperties(GEMFIRE_MANAGER_NAME); HeadlessGfsh gfsh = setUpJmxManagerOnVm0ThenConnect(managerDistributedSystemProperties); // vm 0 // -- // locator/manager assertNotNull(gfsh); // controller vm -- gfsh assertTrue(gfsh.isConnectedAndReady()); setupGemFire(); // vm 1 -- server verifyGemFireSetup(createPeer(getHost(0).getVM(0), managerDistributedSystemProperties)); } @Test public void testGetOnCacheMiss() { doHousekeeping(); CommandStringBuilder command = new CommandStringBuilder(CliStrings.GET); command.addOption(CliStrings.GET__REGIONNAME, USERS_REGION_NAME); command.addOption(CliStrings.GET__KEY, "jonbloom"); assertResult(true, runCommand(command.toString())); command = new CommandStringBuilder(CliStrings.GET); command.addOption(CliStrings.GET__REGIONNAME, USERS_REGION_NAME); command.addOption(CliStrings.GET__KEY, "jondoe"); command.addOption(CliStrings.GET__LOAD, "false"); assertResult(false, runCommand(command.toString())); command = new CommandStringBuilder(CliStrings.GET); command.addOption(CliStrings.GET__REGIONNAME, USERS_REGION_NAME); command.addOption(CliStrings.GET__KEY, "jondoe"); command.addOption(CliStrings.GET__LOAD, "true"); assertResult(true, runCommand(command.toString())); // NOTE test the unspecified default value for the --load-on-cache-miss command = new CommandStringBuilder(CliStrings.GET); command.addOption(CliStrings.GET__REGIONNAME, USERS_REGION_NAME); command.addOption(CliStrings.GET__KEY, "janedoe"); assertResult(true, runCommand(command.toString())); // NOTE now test an absolute cache miss both for in the Region as well as the CacheLoader command = new CommandStringBuilder(CliStrings.GET); command.addOption(CliStrings.GET__REGIONNAME, USERS_REGION_NAME); command.addOption(CliStrings.GET__KEY, "nonexistinguser"); command.addOption(CliStrings.GET__LOAD, "true"); assertResult(false, runCommand(command.toString())); } private static String getRegionPath(final String regionName) { return (regionName.startsWith(Region.SEPARATOR) ? regionName : String.format("%1$s%2$s", Region.SEPARATOR, regionName)); } private static String toString(final Result result) { assert result != null : "The Result object from the command execution was null!"; StringBuilder buffer = new StringBuilder(System.getProperty("line.separator")); while (result.hasNextLine()) { buffer.append(result.nextLine()); buffer.append(System.getProperty("line.separator")); } return buffer.toString(); } private void setupGemFire() throws Exception { initializePeer( createPeer(getHost(0).getVM(1), createDistributedSystemProperties(GEMFIRE_SERVER_NAME))); } private Properties createDistributedSystemProperties(final String gemfireName) { Properties distributedSystemProperties = new Properties(); distributedSystemProperties.setProperty(LOG_LEVEL, GEMFIRE_LOG_LEVEL); distributedSystemProperties.setProperty(NAME, gemfireName); return distributedSystemProperties; } private Peer createPeer(final VM vm, final Properties distributedSystemProperties) { return new Peer(vm, distributedSystemProperties); } private void initializePeer(final Peer peer) throws Exception { peer.run(new SerializableRunnable( String.format("Initializes the '%1$s' with the '%2$s' Region having a CacheLoader.", GEMFIRE_SERVER_NAME, USERS_REGION_NAME)) { @Override public void run() { // create the GemFire Distributed System with custom distribution configuration properties // and settings getSystem(peer.getConfiguration()); Cache cache = getCache(); RegionFactory<String, User> regionFactory = cache.createRegionFactory(RegionShortcut.REPLICATE); regionFactory.setCacheLoader(new UserDataStoreCacheLoader()); regionFactory.setInitialCapacity(51); regionFactory.setKeyConstraint(String.class); regionFactory.setLoadFactor(0.75f); regionFactory.setStatisticsEnabled(false); regionFactory.setValueConstraint(User.class); Region<String, User> users = regionFactory.create(USERS_REGION_NAME); assertNotNull(users); assertEquals("Users", users.getName()); assertEquals("/Users", users.getFullPath()); assertTrue(users.isEmpty()); assertNull(users.put("jonbloom", new User("jonbloom"))); assertFalse(users.isEmpty()); assertEquals(1, users.size()); assertEquals(new User("jonbloom"), users.get("jonbloom")); } }); } private void verifyGemFireSetup(final Peer manager) throws Exception { manager.run(new SerializableRunnable( "Verifies the GemFire Cluster was properly configured and initialized!") { @Override public void run() { final ManagementService managementService = ManagementService.getExistingManagementService(getCache()); WaitCriterion waitOnManagerCriterion = new WaitCriterion() { @Override public boolean done() { ManagerMXBean managerBean = managementService.getManagerMXBean(); DistributedRegionMXBean usersRegionBean = managementService.getDistributedRegionMXBean(getRegionPath(USERS_REGION_NAME)); return !(managerBean == null || usersRegionBean == null); } @Override public String description() { return String.format( "Probing for the GemFire Manager '%1$s' and '%2$s' Region MXBeans...", manager.getName(), USERS_REGION_NAME); } }; waitForCriterion(waitOnManagerCriterion, 30000, 2000, true); } }); } private void doHousekeeping() { runCommand(CliStrings.LIST_MEMBER); runCommand(new CommandStringBuilder(CliStrings.DESCRIBE_MEMBER) .addOption(CliStrings.DESCRIBE_MEMBER__IDENTIFIER, GEMFIRE_SERVER_NAME).toString()); runCommand(CliStrings.LIST_REGION); runCommand(new CommandStringBuilder(CliStrings.DESCRIBE_REGION) .addOption(CliStrings.DESCRIBE_REGION__NAME, USERS_REGION_NAME).toString()); } private void log(final Result result) { log("Result", toString(result)); } private void log(final String tag, final String message) { // System.out.printf("%1$s (%2$s)%n", tag, message); getLogWriter().info(String.format("%1$s (%2$s)%n", tag, message)); } private CommandResult runCommand(final String command) { CommandResult result = executeCommand(command); assertNotNull(result); assertEquals(Result.Status.OK, result.getStatus()); log(result); return result; } private void assertResult(final boolean expectedResult, final CommandResult commandResult) { if (ResultData.TYPE_COMPOSITE.equals(commandResult.getType())) { boolean actualResult = (Boolean) ((CompositeResultData) commandResult.getResultData()) .retrieveSectionByIndex(0).retrieveObject("Result"); assertEquals(expectedResult, actualResult); } else { fail(String.format("Expected composite result data; but was '%1$s'!%n", commandResult.getType())); } } private static final class Peer implements Serializable { private final Properties distributedSystemProperties; private final VM vm; public Peer(final VM vm, final Properties distributedSystemProperties) { assert distributedSystemProperties != null : "The GemFire Distributed System configuration properties and settings cannot be null!"; this.vm = vm; this.distributedSystemProperties = distributedSystemProperties; } public Properties getConfiguration() { return this.distributedSystemProperties; } public String getName() { return getConfiguration().getProperty(NAME); } public VM getVm() { return vm; } public void run(final SerializableRunnableIF runnable) throws Exception { if (getVm() == null) { runnable.run(); } else { getVm().invoke(runnable); } } @Override public String toString() { StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); buffer.append(" {configuration = ").append(getConfiguration()); buffer.append(", name = ").append(getName()); buffer.append(", pid = ").append(getVm().getPid()); buffer.append("}"); return buffer.toString(); } } private static class User implements Serializable { private final String username; public User(final String username) { assert username != null : "The username cannot be null!"; this.username = username; } public String getUsername() { return username; } @Override public boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof User)) { return false; } User that = (User) obj; return this.getUsername().equals(that.getUsername()); } @Override public int hashCode() { int hashValue = 17; hashValue = 37 * hashValue + getUsername().hashCode(); return hashValue; } @Override public String toString() { return getUsername(); } } private static class UserDataStoreCacheLoader implements CacheLoader<String, User>, Serializable { private static final Map<String, User> userDataStore = new HashMap<String, User>(5); static { userDataStore.put("jackhandy", createUser("jackhandy")); userDataStore.put("janedoe", createUser("janedoe")); userDataStore.put("jondoe", createUser("jondoe")); userDataStore.put("piedoe", createUser("piedoe")); userDataStore.put("supertool", createUser("supertool")); } protected static User createUser(final String username) { return new User(username); } @Override public User load(final LoaderHelper<String, User> helper) throws CacheLoaderException { return userDataStore.get(helper.getKey()); } @Override public void close() { userDataStore.clear(); } } }