/* * 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.wicket.protocol.http; import java.security.SecureRandom; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.apache.wicket.util.SlowTests; import org.apache.wicket.util.time.Duration; import org.apache.wicket.util.time.Time; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; /** * @see <a href="https://issues.apache.org/jira/browse/WICKET-3209">WICKET-3209</a> */ @Category(SlowTests.class) public class StoredResponsesMapTest extends Assert { /** * Verifies that {@link StoredResponsesMap} will expire the oldest entry if it is older than 2 * seconds * * @throws Exception */ @Test public void entriesLife2Seconds() throws Exception { StoredResponsesMap map = new StoredResponsesMap(1000, Duration.seconds(2)); assertEquals(0, map.size()); map.put("1", new BufferedWebResponse(null)); assertEquals(1, map.size()); TimeUnit.SECONDS.sleep(3); map.put("2", new BufferedWebResponse(null)); assertEquals(1, map.size()); assertTrue(map.containsKey("2")); } /** * Verifies that getting a value which is expired will return <code>null</code>. * * @throws Exception */ @Test public void getExpiredValue() throws Exception { Time start = Time.now(); Duration timeout = Duration.milliseconds(50); StoredResponsesMap map = new StoredResponsesMap(1000, timeout); assertEquals(0, map.size()); map.put("1", new BufferedWebResponse(null)); assertEquals(1, map.size()); TimeUnit.MILLISECONDS.sleep(timeout.getMilliseconds() * 2); // sleep for twice longer than the timeout assertTrue("The timeout has passed.", Time.now().subtract(start).compareTo(timeout) == 1); Object value = map.get("1"); assertNull(value); } /** * Verifies that {@link StoredResponsesMap} can have only {@link BufferedWebResponse} values */ @Test(expected = IllegalArgumentException.class) public void cannotPutArbitraryValue() { StoredResponsesMap map = new StoredResponsesMap(1000, Duration.days(1)); map.put("1", new Object()); } /** * <a href="https://issues.apache.org/jira/browse/WICKET-3736">WICKET-3736</a> * * Tries to simulate heavy load on the {@link StoredResponsesMap} by putting many entries and * removing randomly them. * * The test is disabled by default because it is slow (~ 30secs). Enable it when we have * categorized tests ({@link Category}) and run slow ones only at Apache CI servers * * @throws InterruptedException */ @Test public void heavyLoad() throws InterruptedException { final int numberOfThreads = 100; final int iterations = 1000; final CountDownLatch startLatch = new CountDownLatch(numberOfThreads); final CountDownLatch endLatch = new CountDownLatch(numberOfThreads); final SecureRandom rnd = new SecureRandom(); final StoredResponsesMap map = new StoredResponsesMap(1000, Duration.seconds(60)); final List<String> keys = new CopyOnWriteArrayList<String>(); final Runnable r = new Runnable() { @Override public void run() { startLatch.countDown(); try { // wait all threads before starting the test startLatch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } for (int i = 0; i < iterations; i++) { String key = "abc" + (rnd.nextDouble() * iterations); keys.add(key); map.put(key, new BufferedWebResponse(null)); int randomMax = keys.size() - 1; int toRemove = randomMax == 0 ? 0 : rnd.nextInt(randomMax); String key2 = keys.get(toRemove); map.remove(key2); } endLatch.countDown(); } }; for (int t = 0; t < numberOfThreads; t++) { new Thread(r).start(); } endLatch.await(); } }