init
This commit is contained in:
361
test/org/apache/catalina/session/Benchmarks.java
Normal file
361
test/org/apache/catalina/session/Benchmarks.java
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.core.StandardHost;
|
||||
|
||||
/**
|
||||
* Named Benchmarks so it is not automatically executed as part of the unit
|
||||
* tests.
|
||||
*/
|
||||
public class Benchmarks {
|
||||
|
||||
/*
|
||||
* Results on markt's 4-core Windows dev box
|
||||
* 1 thread - ~1,400ms
|
||||
* 2 threads - ~2,100ms
|
||||
* 4 threads - ~3,100ms
|
||||
* 16 threads - ~14,700ms
|
||||
*
|
||||
* Results on markt's 2-core OSX dev box
|
||||
* 1 thread - ~1,400ms
|
||||
* 2 threads - ~1,700ms
|
||||
* 4 threads - ~3,500ms
|
||||
* 16 threads - ~14,465ms
|
||||
*/
|
||||
@Test
|
||||
public void testManagerBaseGenerateSessionId() throws Exception {
|
||||
doTestManagerBaseGenerateSessionId(1, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(1, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(1, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(2, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(2, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(2, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(4, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(4, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(4, 1000000);
|
||||
doTestManagerBaseGenerateSessionId(16, 1000000);
|
||||
// Reduce iterations as context switching will slow things down
|
||||
doTestManagerBaseGenerateSessionId(100, 100000);
|
||||
doTestManagerBaseGenerateSessionId(400, 10000);
|
||||
}
|
||||
|
||||
|
||||
private void doTestManagerBaseGenerateSessionId(int threadCount,
|
||||
int iterCount) throws Exception {
|
||||
|
||||
// Create a default session manager
|
||||
StandardManager mgr = new StandardManager();
|
||||
try {
|
||||
mgr.startInternal();
|
||||
} catch (LifecycleException e) {
|
||||
// Ignore - this is expected
|
||||
}
|
||||
mgr.generateSessionId();
|
||||
while (mgr.sessionCreationTiming.size() <
|
||||
ManagerBase.TIMING_STATS_CACHE_SIZE) {
|
||||
mgr.sessionCreationTiming.add(null);
|
||||
}
|
||||
while (mgr.sessionExpirationTiming.size() <
|
||||
ManagerBase.TIMING_STATS_CACHE_SIZE) {
|
||||
mgr.sessionExpirationTiming.add(null);
|
||||
}
|
||||
|
||||
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i] = new Thread(
|
||||
new TestThreadGenerateSessionId(mgr, iterCount));
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
try {
|
||||
threads[i].join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("Threads: ");
|
||||
result.append(threadCount);
|
||||
result.append(", Time(ms): ");
|
||||
result.append(end-start);
|
||||
System.out.println(result.toString());
|
||||
}
|
||||
|
||||
|
||||
private static final class TestThreadGenerateSessionId implements Runnable {
|
||||
|
||||
private ManagerBase mgr;
|
||||
private int count;
|
||||
|
||||
public TestThreadGenerateSessionId(ManagerBase mgr, int count) {
|
||||
this.mgr = mgr;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
mgr.generateSessionId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Results on markt's 4-core Windows dev box
|
||||
* 1 thread - ~3,800ms
|
||||
* 2 threads - ~6,700ms
|
||||
* 4 threads - ~11,000ms
|
||||
* 16 threads - ~43,500ms
|
||||
*
|
||||
* Results on markt's 2-core OSX dev box
|
||||
* 1 thread - ~4,100ms
|
||||
* 2 threads - ~5,700ms
|
||||
* 4 threads - ~11,700ms
|
||||
* 16 threads - ~45,600ms
|
||||
*/
|
||||
@Test
|
||||
public void testManagerBaseCreateSession() throws LifecycleException {
|
||||
doTestManagerBaseCreateSession(1, 100000);
|
||||
doTestManagerBaseCreateSession(2, 1000000);
|
||||
doTestManagerBaseCreateSession(4, 1000000);
|
||||
doTestManagerBaseCreateSession(16, 1000000);
|
||||
// Reduce iterations as context switching will slow things down
|
||||
doTestManagerBaseCreateSession(100, 100000);
|
||||
doTestManagerBaseCreateSession(400, 10000);
|
||||
}
|
||||
|
||||
|
||||
private void doTestManagerBaseCreateSession(int threadCount,
|
||||
int iterCount) throws LifecycleException {
|
||||
|
||||
// Create a default session manager
|
||||
StandardManager mgr = new StandardManager();
|
||||
mgr.setPathname(null);
|
||||
Host host = new StandardHost();
|
||||
host.setName("unittest");
|
||||
Context context = new StandardContext();
|
||||
context.setPath("");
|
||||
context.setParent(host);
|
||||
mgr.setContext(context);
|
||||
mgr.start();
|
||||
mgr.generateSessionId();
|
||||
while (mgr.sessionCreationTiming.size() <
|
||||
ManagerBase.TIMING_STATS_CACHE_SIZE) {
|
||||
mgr.sessionCreationTiming.add(null);
|
||||
}
|
||||
while (mgr.sessionExpirationTiming.size() <
|
||||
ManagerBase.TIMING_STATS_CACHE_SIZE) {
|
||||
mgr.sessionExpirationTiming.add(null);
|
||||
}
|
||||
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i] = new Thread(
|
||||
new TestThreadCreateSession(mgr, iterCount));
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
try {
|
||||
threads[i].join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("Threads: ");
|
||||
result.append(threadCount);
|
||||
result.append(", Time(ms): ");
|
||||
result.append(end-start);
|
||||
System.out.println(result.toString());
|
||||
}
|
||||
|
||||
private static final class TestThreadCreateSession implements Runnable {
|
||||
|
||||
private ManagerBase mgr;
|
||||
private int count;
|
||||
|
||||
public TestThreadCreateSession(ManagerBase mgr, int count) {
|
||||
this.mgr = mgr;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
Session session = mgr.createSession(mgr.generateSessionId());
|
||||
session.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SecureRandom vs. reading /dev/urandom. Very different performance noted
|
||||
* on some platforms.
|
||||
*
|
||||
* Results on markt's 4-core Windows dev box
|
||||
* SecureRandom /dev/urandom
|
||||
* 1 thread - ~766ms N/A
|
||||
* 2 threads - ~843ms N/A
|
||||
* 4 threads - ~766ms N/A
|
||||
*
|
||||
* Results on markt's 2-core OSX dev box
|
||||
* SecureRandom /dev/urandom
|
||||
* 1 thread - ~759ms ~3,500ms
|
||||
* 2 threads - ~725ms ~5,200ms
|
||||
* 4 threads - ~1,265ms ~10,500ms
|
||||
*/
|
||||
@Test
|
||||
public void testSecureRandomVsDevURandom() throws Exception {
|
||||
doTestSecureRandomVsDevURandom(1, 1000000);
|
||||
doTestSecureRandomVsDevURandom(2, 1000000);
|
||||
doTestSecureRandomVsDevURandom(4, 1000000);
|
||||
}
|
||||
|
||||
private void doTestSecureRandomVsDevURandom(int threadCount, int iterCount)
|
||||
throws Exception {
|
||||
doTestSecureRandomVsDevURandomInner(threadCount, iterCount, true);
|
||||
doTestSecureRandomVsDevURandomInner(threadCount, iterCount, false);
|
||||
}
|
||||
|
||||
private void doTestSecureRandomVsDevURandomInner(int threadCount,
|
||||
int iterCount, boolean useSecureRandom) throws Exception {
|
||||
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
if (useSecureRandom) {
|
||||
threads[i] = new Thread(new TestThreadSecureRandom(iterCount));
|
||||
} else {
|
||||
threads[i] = new Thread(new TestThreadDevUrandom(iterCount));
|
||||
}
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
try {
|
||||
threads[i].join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
if (useSecureRandom) {
|
||||
result.append("SecureRandom ");
|
||||
} else {
|
||||
result.append("/dev/urandom ");
|
||||
}
|
||||
result.append("Threads: ");
|
||||
result.append(threadCount);
|
||||
result.append(", Time(ms): ");
|
||||
result.append(end-start);
|
||||
System.out.println(result.toString());
|
||||
}
|
||||
|
||||
private static final class TestThreadSecureRandom implements Runnable {
|
||||
|
||||
private SecureRandom secureRandom;
|
||||
private byte[] bytes = new byte[16];
|
||||
private int count;
|
||||
|
||||
TestThreadSecureRandom(int iterCount) throws Exception {
|
||||
this.count = iterCount;
|
||||
this.secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
secureRandom.nextBytes(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class TestThreadDevUrandom implements Runnable {
|
||||
|
||||
private InputStream is;
|
||||
private byte[] bytes = new byte[16];
|
||||
private int count;
|
||||
|
||||
TestThreadDevUrandom(int iterCount) {
|
||||
try {
|
||||
is = new FileInputStream("/dev/urandom");
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.count = iterCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int read = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
read = is.read(bytes);
|
||||
if (read < bytes.length) {
|
||||
throw new IOException("Only read " + read + " bytes");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
test/org/apache/catalina/session/FileStoreTest.java
Normal file
101
test/org/apache/catalina/session/FileStoreTest.java
Normal file
@@ -0,0 +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 org.apache.catalina.session;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.tomcat.unittest.TesterContext;
|
||||
import org.apache.tomcat.unittest.TesterServletContext;
|
||||
import org.apache.tomcat.util.http.fileupload.FileUtils;
|
||||
|
||||
public class FileStoreTest {
|
||||
|
||||
private static final String SESS_TEMPPATH = "SESS_TEMP";
|
||||
private static final File dir = new File(SESS_TEMPPATH);
|
||||
private static FileStore fileStore;
|
||||
private static File file1 = new File(SESS_TEMPPATH + "/tmp1.session");
|
||||
private static File file2 = new File(SESS_TEMPPATH + "/tmp2.session");
|
||||
private static Manager manager = new StandardManager();
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
TesterContext testerContext = new TesterContext();
|
||||
testerContext.setServletContext(new TesterServletContext());
|
||||
manager.setContext(testerContext);
|
||||
fileStore = new FileStore();
|
||||
fileStore.setManager(manager);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() throws IOException {
|
||||
FileUtils.cleanDirectory(dir);
|
||||
FileUtils.deleteDirectory(dir);
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeEachTest() throws IOException {
|
||||
fileStore.setDirectory(SESS_TEMPPATH);
|
||||
if (!dir.mkdir()) {
|
||||
Assert.fail();
|
||||
}
|
||||
if (!file1.createNewFile()) {
|
||||
Assert.fail();
|
||||
}
|
||||
if (!file2.createNewFile()) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getSize() throws Exception {
|
||||
Assert.assertEquals(2, fileStore.getSize());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void clear() throws Exception {
|
||||
fileStore.clear();
|
||||
Assert.assertEquals(0, fileStore.getSize());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void keys() throws Exception {
|
||||
Assert.assertArrayEquals(new String[]{"tmp1", "tmp2"}, fileStore.keys());
|
||||
fileStore.clear();
|
||||
Assert.assertArrayEquals(new String[]{}, fileStore.keys());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void removeTest() throws Exception {
|
||||
fileStore.remove("tmp1");
|
||||
Assert.assertEquals(1, fileStore.getSize());
|
||||
}
|
||||
}
|
||||
161
test/org/apache/catalina/session/TestPersistentManager.java
Normal file
161
test/org/apache/catalina/session/TestPersistentManager.java
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
import javax.servlet.http.HttpSessionListener;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.Store;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.RequestFacade;
|
||||
import org.apache.tomcat.unittest.TesterContext;
|
||||
import org.apache.tomcat.unittest.TesterHost;
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IAnswer;
|
||||
|
||||
public class TestPersistentManager {
|
||||
|
||||
@Test
|
||||
public void testMinIdleSwap() throws Exception {
|
||||
PersistentManager manager = new PersistentManager();
|
||||
manager.setStore(new TesterStore());
|
||||
|
||||
Host host = new TesterHost();
|
||||
Context context = new TesterContext();
|
||||
context.setParent(host);
|
||||
|
||||
manager.setContext(context);
|
||||
|
||||
manager.setMaxActiveSessions(2);
|
||||
manager.setMinIdleSwap(0);
|
||||
|
||||
manager.start();
|
||||
|
||||
// Create the maximum number of sessions
|
||||
manager.createSession(null);
|
||||
manager.createSession(null);
|
||||
|
||||
// Given the minIdleSwap settings, this should swap one out to get below
|
||||
// the limit
|
||||
manager.processPersistenceChecks();
|
||||
Assert.assertEquals(1, manager.getActiveSessions());
|
||||
Assert.assertEquals(2, manager.getActiveSessionsFull());
|
||||
|
||||
manager.createSession(null);
|
||||
Assert.assertEquals(2, manager.getActiveSessions());
|
||||
Assert.assertEquals(3, manager.getActiveSessionsFull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug62175() throws Exception {
|
||||
final PersistentManager manager = new PersistentManager();
|
||||
final AtomicInteger sessionExpireCounter = new AtomicInteger();
|
||||
|
||||
Store mockStore = EasyMock.createNiceMock(Store.class);
|
||||
EasyMock.expect(mockStore.load(EasyMock.anyString())).andAnswer(new IAnswer<Session>() {
|
||||
|
||||
@Override
|
||||
public Session answer() throws Throwable {
|
||||
return timedOutSession(manager, sessionExpireCounter);
|
||||
}
|
||||
}).anyTimes();
|
||||
|
||||
EasyMock.replay(mockStore);
|
||||
|
||||
manager.setStore(mockStore);
|
||||
|
||||
Host host = new TesterHost();
|
||||
|
||||
final RequestCachingSessionListener requestCachingSessionListener = new RequestCachingSessionListener();
|
||||
|
||||
final Context context = new TesterContext() {
|
||||
|
||||
@Override
|
||||
public Object[] getApplicationLifecycleListeners() {
|
||||
return new Object[] { requestCachingSessionListener };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manager getManager() {
|
||||
return manager;
|
||||
}
|
||||
};
|
||||
context.setParent(host);
|
||||
|
||||
Request req = new Request() {
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
};
|
||||
req.setRequestedSessionId("invalidSession");
|
||||
HttpServletRequest request = new RequestFacade(req);
|
||||
requestCachingSessionListener.request = request;
|
||||
|
||||
manager.setContext(context);
|
||||
|
||||
manager.start();
|
||||
|
||||
Assert.assertNull(request.getSession(false));
|
||||
Assert.assertEquals(1, sessionExpireCounter.get());
|
||||
|
||||
}
|
||||
|
||||
private static class RequestCachingSessionListener implements HttpSessionListener {
|
||||
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public void sessionCreated(HttpSessionEvent se) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionDestroyed(HttpSessionEvent se) {
|
||||
request.getSession(false);
|
||||
}
|
||||
}
|
||||
|
||||
private StandardSession timedOutSession(final PersistentManager manager, final AtomicInteger counter) {
|
||||
StandardSession timedOutSession = new StandardSession(manager) {
|
||||
private static final long serialVersionUID = -5910605558747844210L;
|
||||
|
||||
@Override
|
||||
public void expire() {
|
||||
counter.incrementAndGet();
|
||||
super.expire();
|
||||
}
|
||||
};
|
||||
timedOutSession.isValid = true;
|
||||
timedOutSession.expiring = false;
|
||||
timedOutSession.maxInactiveInterval = 1;
|
||||
timedOutSession.lastAccessedTime = 0;
|
||||
timedOutSession.id = "invalidSession";
|
||||
return timedOutSession;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.catalina.valves.PersistentValve;
|
||||
|
||||
public class TestPersistentManagerIntegration extends TomcatBaseTest {
|
||||
|
||||
private final String ACTIVITY_CHECK = "org.apache.catalina.session.StandardSession.ACTIVITY_CHECK";
|
||||
|
||||
private String oldActivityCheck;
|
||||
|
||||
/**
|
||||
* As documented in config/manager.html, the "ACTIVITY_CHECK" property must
|
||||
* be set to "true" for PersistentManager to function correctly.
|
||||
*/
|
||||
@Before
|
||||
public void setActivityCheck() {
|
||||
oldActivityCheck = System.setProperty(ACTIVITY_CHECK, "true");
|
||||
}
|
||||
|
||||
@After
|
||||
public void resetActivityCheck() {
|
||||
if (oldActivityCheck != null) {
|
||||
System.setProperty(ACTIVITY_CHECK, oldActivityCheck);
|
||||
} else {
|
||||
System.clearProperty(ACTIVITY_CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait enough for the system clock to update its value. On some systems
|
||||
* (e.g. old Windows) the clock granularity is tens of milliseconds.
|
||||
*/
|
||||
private void waitForClockUpdate() throws InterruptedException {
|
||||
long startTime = System.currentTimeMillis();
|
||||
int waitTime = 1;
|
||||
do {
|
||||
Thread.sleep(waitTime);
|
||||
waitTime *= 10;
|
||||
} while (System.currentTimeMillis() == startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait while session access counter has a positive value.
|
||||
*/
|
||||
private void waitWhileSessionIsActive(StandardSession session)
|
||||
throws InterruptedException {
|
||||
long maxWaitTime = System.currentTimeMillis() + 60000;
|
||||
AtomicInteger accessCount = session.accessCount;
|
||||
while (accessCount.get() > 0) {
|
||||
// Wait until o.a.c.connector.Request.recycle() completes,
|
||||
// as it updates lastAccessedTime.
|
||||
Assert.assertTrue(System.currentTimeMillis() < maxWaitTime);
|
||||
Thread.sleep(200);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noSessionCreate_57637() throws IOException, LifecycleException {
|
||||
|
||||
// Setup Tomcat instance
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
// No file system docBase required
|
||||
StandardContext ctx = (StandardContext) tomcat.addContext("", null);
|
||||
ctx.setDistributable(true);
|
||||
|
||||
Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet());
|
||||
ctx.addServletMappingDecoded("/dummy", "DummyServlet");
|
||||
|
||||
PersistentManager manager = new PersistentManager();
|
||||
TesterStore store = new TesterStore();
|
||||
|
||||
manager.setStore(store);
|
||||
manager.setMaxIdleBackup(0);
|
||||
ctx.setManager(manager);
|
||||
ctx.addValve(new PersistentValve());
|
||||
tomcat.start();
|
||||
Assert.assertEquals(manager.getActiveSessions(), 0);
|
||||
Assert.assertTrue("No sessions managed", manager.getSessionIdsFull().isEmpty());
|
||||
Assert.assertEquals(
|
||||
"NO_SESSION",
|
||||
getUrl(
|
||||
"http://localhost:" + getPort()
|
||||
+ "/dummy?no_create_session=true").toString());
|
||||
Assert.assertEquals(manager.getActiveSessions(), 0);
|
||||
Assert.assertTrue("No sessions where created", manager.getSessionIdsFull().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSessionAndPassivate() throws IOException, LifecycleException, ClassNotFoundException {
|
||||
|
||||
// Setup Tomcat instance
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
// No file system docBase required
|
||||
StandardContext ctx = (StandardContext) tomcat.addContext("", null);
|
||||
ctx.setDistributable(true);
|
||||
|
||||
Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet());
|
||||
ctx.addServletMappingDecoded("/dummy", "DummyServlet");
|
||||
|
||||
PersistentManager manager = new PersistentManager();
|
||||
TesterStore store = new TesterStore();
|
||||
|
||||
manager.setStore(store);
|
||||
manager.setMaxIdleBackup(0);
|
||||
ctx.setManager(manager);
|
||||
ctx.addValve(new PersistentValve());
|
||||
tomcat.start();
|
||||
Assert.assertEquals("No active sessions", manager.getActiveSessions(), 0);
|
||||
Assert.assertTrue("No sessions managed", manager.getSessionIdsFull().isEmpty());
|
||||
String sessionId = getUrl(
|
||||
"http://localhost:" + getPort()
|
||||
+ "/dummy?no_create_session=false").toString();
|
||||
Assert.assertNotNull("Session is stored", store.load(sessionId));
|
||||
Assert.assertEquals("All sessions are passivated", manager.getActiveSessions(), 0);
|
||||
Assert.assertTrue("One session was created", !manager.getSessionIdsFull().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backsUpOnce_56698() throws IOException, LifecycleException,
|
||||
InterruptedException {
|
||||
|
||||
// Setup Tomcat instance
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
ctx.setDistributable(true);
|
||||
|
||||
Tomcat.addServlet(ctx, "DummyServlet", new DummyServlet());
|
||||
ctx.addServletMappingDecoded("/dummy", "DummyServlet");
|
||||
|
||||
PersistentManager manager = new PersistentManager();
|
||||
TesterStore store = new TesterStore();
|
||||
|
||||
manager.setStore(store);
|
||||
manager.setMaxIdleBackup(0);
|
||||
ctx.setManager(manager);
|
||||
tomcat.start();
|
||||
String sessionId = getUrl("http://localhost:" + getPort() + "/dummy")
|
||||
.toString();
|
||||
|
||||
// Note: PersistenceManager.findSession() silently updates
|
||||
// session.lastAccessedTime, so call it only once before other work.
|
||||
Session session = manager.findSession(sessionId);
|
||||
|
||||
// Wait until request processing ends, as Request.recycle() updates
|
||||
// session.lastAccessedTime via session.endAccess().
|
||||
waitWhileSessionIsActive((StandardSession) session);
|
||||
|
||||
long lastAccessedTime = session.getLastAccessedTimeInternal();
|
||||
|
||||
// Session should be idle at least for 0 second (maxIdleBackup)
|
||||
// to be eligible for persistence, thus no need to wait.
|
||||
|
||||
// Waiting a bit, to catch changes in last accessed time of a session
|
||||
waitForClockUpdate();
|
||||
|
||||
manager.processPersistenceChecks();
|
||||
Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds());
|
||||
Assert.assertEquals(lastAccessedTime, session.getLastAccessedTimeInternal());
|
||||
|
||||
// session was not accessed, so no save will be performed
|
||||
waitForClockUpdate();
|
||||
manager.processPersistenceChecks();
|
||||
Assert.assertEquals(Arrays.asList(sessionId), store.getSavedIds());
|
||||
Assert.assertEquals(lastAccessedTime, session.getLastAccessedTimeInternal());
|
||||
|
||||
// access session
|
||||
session.access();
|
||||
session.endAccess();
|
||||
|
||||
// session was accessed, so it will be saved once again
|
||||
manager.processPersistenceChecks();
|
||||
Assert.assertEquals(Arrays.asList(sessionId, sessionId),
|
||||
store.getSavedIds());
|
||||
|
||||
// session was not accessed, so once again no save will happen
|
||||
manager.processPersistenceChecks();
|
||||
Assert.assertEquals(Arrays.asList(sessionId, sessionId),
|
||||
store.getSavedIds());
|
||||
}
|
||||
|
||||
private static class DummyServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = -3696433049266123995L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
boolean createSession = !Boolean.parseBoolean(req
|
||||
.getParameter("no_create_session"));
|
||||
HttpSession session = req.getSession(createSession);
|
||||
if (session == null) {
|
||||
resp.getWriter().print("NO_SESSION");
|
||||
} else {
|
||||
String id = session.getId();
|
||||
resp.getWriter().print(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
154
test/org/apache/catalina/session/TestStandardSession.java
Normal file
154
test/org/apache/catalina/session/TestStandardSession.java
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
|
||||
public class TestStandardSession {
|
||||
|
||||
private static final Manager TEST_MANAGER;
|
||||
|
||||
static {
|
||||
TEST_MANAGER = new StandardManager();
|
||||
TEST_MANAGER.setContext(new StandardContext());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerializationEmpty() throws Exception {
|
||||
|
||||
StandardSession s1 = new StandardSession(TEST_MANAGER);
|
||||
s1.setValid(true);
|
||||
StandardSession s2 = serializeThenDeserialize(s1);
|
||||
|
||||
validateSame(s1, s2, 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerializationSimple01() throws Exception {
|
||||
|
||||
StandardSession s1 = new StandardSession(TEST_MANAGER);
|
||||
s1.setValid(true);
|
||||
s1.setAttribute("attr01", "value01");
|
||||
|
||||
StandardSession s2 = serializeThenDeserialize(s1);
|
||||
|
||||
validateSame(s1, s2, 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerializationSimple02() throws Exception {
|
||||
|
||||
StandardSession s1 = new StandardSession(TEST_MANAGER);
|
||||
s1.setValid(true);
|
||||
s1.setAttribute("attr01", new NonSerializable());
|
||||
|
||||
StandardSession s2 = serializeThenDeserialize(s1);
|
||||
|
||||
validateSame(s1, s2, 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSerializationSimple03() throws Exception {
|
||||
|
||||
StandardSession s1 = new StandardSession(TEST_MANAGER);
|
||||
s1.setValid(true);
|
||||
s1.setAttribute("attr01", "value01");
|
||||
s1.setAttribute("attr02", new NonSerializable());
|
||||
|
||||
StandardSession s2 = serializeThenDeserialize(s1);
|
||||
|
||||
validateSame(s1, s2, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* See Bug 58284
|
||||
*/
|
||||
@Test
|
||||
public void serializeSkipsNonSerializableAttributes() throws Exception {
|
||||
final String nonSerializableKey = "nonSerializable";
|
||||
final String nestedNonSerializableKey = "nestedNonSerializable";
|
||||
final String serializableKey = "serializable";
|
||||
final Object serializableValue = "foo";
|
||||
|
||||
StandardSession s1 = new StandardSession(TEST_MANAGER);
|
||||
s1.setValid(true);
|
||||
Map<String, NonSerializable> value = new HashMap<>();
|
||||
value.put("key", new NonSerializable());
|
||||
s1.setAttribute(nestedNonSerializableKey, value);
|
||||
s1.setAttribute(serializableKey, serializableValue);
|
||||
s1.setAttribute(nonSerializableKey, new NonSerializable());
|
||||
|
||||
StandardSession s2 = serializeThenDeserialize(s1);
|
||||
|
||||
Assert.assertNull(s2.getAttribute(nestedNonSerializableKey));
|
||||
Assert.assertNull(s2.getAttribute(nonSerializableKey));
|
||||
Assert.assertEquals(serializableValue, s2.getAttribute(serializableKey));
|
||||
}
|
||||
|
||||
|
||||
private StandardSession serializeThenDeserialize(StandardSession source)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
source.writeObjectData(oos);
|
||||
|
||||
StandardSession dest = new StandardSession(TEST_MANAGER);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
dest.readObjectData(ois);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
private void validateSame(StandardSession s1, StandardSession s2, int expectedCount) {
|
||||
int count = 0;
|
||||
Enumeration<String> names = s1.getAttributeNames();
|
||||
while (names.hasMoreElements()) {
|
||||
count ++;
|
||||
String name = names.nextElement();
|
||||
Object v1 = s1.getAttribute(name);
|
||||
Object v2 = s2.getAttribute(name);
|
||||
|
||||
Assert.assertEquals(v1, v2);
|
||||
}
|
||||
|
||||
Assert.assertEquals(expectedCount, count);
|
||||
}
|
||||
|
||||
|
||||
private static class NonSerializable {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.ha.tcp.SimpleTcpCluster;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
|
||||
public class TestStandardSessionIntegration extends TomcatBaseTest {
|
||||
|
||||
/*
|
||||
* Test session.invalidate() in a clustered environment.
|
||||
*/
|
||||
@Test
|
||||
public void testBug56578a() throws Exception {
|
||||
doTestInvalidate(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBug56578b() throws Exception {
|
||||
doTestInvalidate(false);
|
||||
}
|
||||
|
||||
private void doTestInvalidate(boolean useClustering) throws Exception {
|
||||
// Setup Tomcat instance
|
||||
Tomcat tomcat = getTomcatInstance();
|
||||
|
||||
// No file system docBase required
|
||||
Context ctx = tomcat.addContext("", null);
|
||||
|
||||
Tomcat.addServlet(ctx, "bug56578", new Bug56578Servlet());
|
||||
ctx.addServletMappingDecoded("/bug56578", "bug56578");
|
||||
|
||||
if (useClustering) {
|
||||
tomcat.getEngine().setCluster(new SimpleTcpCluster());
|
||||
ctx.setDistributable(true);
|
||||
ctx.setManager(ctx.getCluster().createManager(""));
|
||||
}
|
||||
tomcat.start();
|
||||
|
||||
ByteChunk res = getUrl("http://localhost:" + getPort() + "/bug56578");
|
||||
Assert.assertEquals("PASS", res.toString());
|
||||
}
|
||||
|
||||
private static class Bug56578Servlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException {
|
||||
resp.setContentType("text/plain");
|
||||
resp.setCharacterEncoding("UTF-8");
|
||||
PrintWriter pw = resp.getWriter();
|
||||
|
||||
HttpSession session = req.getSession(true);
|
||||
session.invalidate();
|
||||
|
||||
// Ugly but the easiest way to test of the session is valid or not
|
||||
boolean result;
|
||||
try {
|
||||
session.getCreationTime();
|
||||
result = false;
|
||||
} catch (IllegalStateException ise) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
pw.print("PASS");
|
||||
} else {
|
||||
pw.print("FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
90
test/org/apache/catalina/session/TesterStore.java
Normal file
90
test/org/apache/catalina/session/TesterStore.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.Store;
|
||||
|
||||
class TesterStore implements Store {
|
||||
|
||||
private Manager manager;
|
||||
private Map<String, Session> sessions = new HashMap<>();
|
||||
private List<String> savedIds = new ArrayList<>();
|
||||
|
||||
List<String> getSavedIds() {
|
||||
return savedIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manager getManager() {
|
||||
return this.manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setManager(Manager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() throws IOException {
|
||||
return savedIds.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] keys() throws IOException {
|
||||
return new ArrayList<>(sessions.keySet()).toArray(new String[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session load(String id) throws ClassNotFoundException,
|
||||
IOException {
|
||||
return sessions.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String id) throws IOException {
|
||||
sessions.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Session session) throws IOException {
|
||||
sessions.put(session.getId(), session);
|
||||
savedIds.add(session.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
147
test/org/apache/catalina/session/Threading.java
Normal file
147
test/org/apache/catalina/session/Threading.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.catalina.session;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* The design of the session manager depends on the thread-safety - or not - of
|
||||
* a number of classes. In some cases the Javadoc is unclear on the
|
||||
* thread-safety of a class. These tests were written to test the thread-safety
|
||||
* of key classes.
|
||||
*
|
||||
* Named Threading so it is not automatically executed as part of the unit
|
||||
* tests.
|
||||
*/
|
||||
public class Threading {
|
||||
|
||||
/*
|
||||
* {@link FileInputStream#read(byte[])} and related methods are all native
|
||||
* methods so it isn't immediately obvious if they are thread-safe or not.
|
||||
*
|
||||
* <pre>
|
||||
* Windows JDK 1.6.0_22_x64 - Thread safe
|
||||
* OSX JDK 1.6.0_22_x64 - Not thread safe
|
||||
* OSX JDK 1.7.0_51_x64 - Not thread safe
|
||||
* </pre>
|
||||
*
|
||||
* Therefore, have to assume that {@link FileInputStream#read(byte[])} is
|
||||
* not thread safe.
|
||||
*/
|
||||
@Test
|
||||
public void testFileInputStream() throws Exception {
|
||||
doTestFileInputStream(1);
|
||||
doTestFileInputStream(2);
|
||||
doTestFileInputStream(4);
|
||||
doTestFileInputStream(16);
|
||||
}
|
||||
|
||||
public void doTestFileInputStream(int threadCount) throws Exception {
|
||||
|
||||
// Assumes "ant release" has been run
|
||||
// Will need to be updated as new releases are made
|
||||
File file = new File(
|
||||
"./output/release/v8.0.15-dev/bin/apache-tomcat-8.0.15-dev.zip");
|
||||
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
FisReaderThread[] runnables = new FisReaderThread[threadCount];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
runnables[i] = new FisReaderThread(fis);
|
||||
threads[i] = new Thread(runnables[i]);
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
threads[i].start();
|
||||
}
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
try {
|
||||
threads[i].join();
|
||||
if (runnables[i].isfailed()) {
|
||||
Assert.fail();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
long byteCount = 0;
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
byteCount += runnables[i].getByteCount();
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("Threads: ");
|
||||
result.append(threadCount);
|
||||
result.append(", Time(ms): ");
|
||||
result.append(end-start);
|
||||
result.append(", Bytes: ");
|
||||
result.append(byteCount);
|
||||
System.out.println(result.toString());
|
||||
}
|
||||
|
||||
private static final class FisReaderThread implements Runnable {
|
||||
|
||||
private FileInputStream fis;
|
||||
// Small buffer to make the process slow
|
||||
private byte[] buffer = new byte[4];
|
||||
private long byteCount = 0;
|
||||
private boolean fail = false;
|
||||
|
||||
public FisReaderThread(FileInputStream fis) {
|
||||
this.fis = fis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int read = 0;
|
||||
while (read > -1) {
|
||||
byteCount += read;
|
||||
try {
|
||||
// Uncomment the sync block to test adding the sync fixes
|
||||
// issues on platforms where fis is not thread-safe
|
||||
// synchronized (fis) {
|
||||
read = fis.read(buffer);
|
||||
//}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail = true;
|
||||
read = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getByteCount() {
|
||||
return byteCount;
|
||||
}
|
||||
|
||||
public boolean isfailed() {
|
||||
return fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user