/* * 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.cache30; import org.apache.geode.cache.*; import org.apache.geode.cache.Region.Entry; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.cache.LocalRegion; import org.apache.geode.test.junit.categories.FlakyTest; import org.apache.geode.test.junit.categories.IntegrationTest; import com.jayway.awaitility.core.ConditionTimeoutException; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import java.util.Properties; import java.util.concurrent.TimeUnit; import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; import static com.jayway.awaitility.Awaitility.with; import static org.junit.Assert.fail; /** * Test for Bug 44418. * * If a new expiration time is specified that is shorter than an existing one, ensure the new * shorter time is honored. * * @since GemFire 7.0 */ @Category(IntegrationTest.class) @SuppressWarnings({"unchecked", "rawtypes"}) public class Bug44418JUnitTest { // TODO: rename this test to non-ticket descriptive name DistributedSystem ds; Cache cache; private static final int LONG_WAIT_MS = 1000 * 60 * 3; // Initial expiration time for entry private static final int TEST_WAIT_MS = 1000 * 60 * 1; // How long to wait for entry to expire private static final int SHORT_WAIT_MS = 1; // New short expiration time for entry private static final int POLL_INTERVAL_MS = 1; // How often to check for expiration private static final String TEST_KEY = "key"; @Category(FlakyTest.class) // GEODE-1139: time sensitive, thread sleep, expiration @Test public void testPut() throws Exception { System.setProperty(LocalRegion.EXPIRY_MS_PROPERTY, "true"); try { final Region r = this.cache.createRegionFactory(RegionShortcut.LOCAL).setStatisticsEnabled(true) .setCustomEntryTimeToLive(new CustomExpiryTestClass()).create("bug44418"); r.put(TEST_KEY, "longExpire"); // should take LONG_WAIT_MS to expire. // Now update it with a short time to live r.put(TEST_KEY, "quickExpire"); if (!awaitExpiration(r, TEST_KEY)) { fail(SHORT_WAIT_MS + " ms expire did not happen after waiting " + TEST_WAIT_MS + " ms"); } } finally { System.getProperties().remove(LocalRegion.EXPIRY_MS_PROPERTY); } } @Category(FlakyTest.class) // GEODE-924: expiration, time sensitive, expects action in 1 second @Test public void testGet() throws Exception { System.setProperty(LocalRegion.EXPIRY_MS_PROPERTY, "true"); try { final Region r = this.cache.createRegionFactory(RegionShortcut.LOCAL).setStatisticsEnabled(true) .setCustomEntryIdleTimeout(new CustomExpiryTestClass()).create("bug44418"); r.put(TEST_KEY, "longExpire"); // should take LONG_WAIT_MS to expire. // Now set a short idle time r.get(TEST_KEY); if (!awaitExpiration(r, TEST_KEY)) { fail(SHORT_WAIT_MS + " ms expire did not happen after waiting " + TEST_WAIT_MS + " ms"); } } finally { System.getProperties().remove(LocalRegion.EXPIRY_MS_PROPERTY); } } private boolean awaitExpiration(Region r, Object key) { // Return true if entry expires. We only wait // TEST_WAIT_MS. If we need to wait that long for // a SHORT_WAIT_MS to expire then the expiration // is probably still set at LONG_WAIT_MS. try { with().pollInterval(POLL_INTERVAL_MS, TimeUnit.MILLISECONDS).await() .atMost(TEST_WAIT_MS, TimeUnit.MILLISECONDS).until(() -> !r.containsValueForKey(key)); } catch (ConditionTimeoutException toe) { return false; } return true; } @After public void tearDown() throws Exception { if (this.cache != null) { this.cache.close(); this.cache = null; } if (this.ds != null) { this.ds.disconnect(); this.ds = null; } } @Before public void setUp() throws Exception { Properties props = new Properties(); props.setProperty(MCAST_PORT, "0"); props.setProperty(LOCATORS, ""); this.ds = DistributedSystem.connect(props); this.cache = CacheFactory.create(this.ds); } private class CustomExpiryTestClass implements CustomExpiry { private boolean secondTime; @Override public void close() {} @Override public ExpirationAttributes getExpiry(Entry entry) { ExpirationAttributes result; if (!this.secondTime) { result = new ExpirationAttributes(LONG_WAIT_MS); // Set long expiration first time entry // referenced this.secondTime = true; } else { result = new ExpirationAttributes(SHORT_WAIT_MS); // Set short expiration second time entry // referenced } return result; } } }