This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new e3a6822e9d Add a (disabled by default) test case for BZ 69781 e3a6822e9d is described below commit e3a6822e9d4d0d7f7166433f7df1e661dd5c2a77 Author: Mark Thomas <ma...@apache.org> AuthorDate: Fri Aug 22 08:51:30 2025 +0100 Add a (disabled by default) test case for BZ 69781 --- .../session/TesterFileStoreConcurrency.java | 178 ++++++++++++++++++ .../org/apache/catalina/session/TesterManager.java | 200 +++++++++++++++++++++ 2 files changed, 378 insertions(+) diff --git a/test/org/apache/catalina/session/TesterFileStoreConcurrency.java b/test/org/apache/catalina/session/TesterFileStoreConcurrency.java new file mode 100644 index 0000000000..650e17e3c6 --- /dev/null +++ b/test/org/apache/catalina/session/TesterFileStoreConcurrency.java @@ -0,0 +1,178 @@ +/* + * 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 org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.startup.ExpandWar; +import org.apache.tomcat.unittest.TesterContext; + +/* + * Test for https://bz.apache.org/bugzilla/show_bug.cgi?id=69781 + * + * The test currently fails almost instantly on markt's desktop with a 5s run time. + * + * This needs to be run manually. It will not run as part of the standard unit tests as it is named "Tester...". This + * could be changed once the bug has been fixed. + */ +public class TesterFileStoreConcurrency { + + private static final int TEST_RUN_TIME_MS = 5000; + + private static final FileStore FILE_STORE = new FileStore(); + private static final String STORE_DIR = "STORE_TMP"; + private static final File STORE_FILE = new File(STORE_DIR); + + private static final int SESSION_COUNT = 10; + private static final Session[] SESSIONS = new Session[SESSION_COUNT]; + + + @BeforeClass + public static void setup() { + Context context = new TesterContext(); + Manager manager = new TesterManager(); + manager.setContext(context); + for (int i = 0; i < SESSION_COUNT; i++) { + SESSIONS[i] = new StandardSession(null); + SESSIONS[i].setManager(manager); + SESSIONS[i].setId(Integer.toString(i)); + } + + FILE_STORE.setDirectory(STORE_FILE.getAbsolutePath()); + FILE_STORE.setManager(manager); + } + + + @AfterClass + public static void cleanUp() { + ExpandWar.delete(STORE_FILE); + } + + + @Test + public void testConcurrency() throws Exception { + SaveTask saveTask = new SaveTask(); + Thread saveThread = new Thread(saveTask); + saveThread.start(); + + LoadTask loadTask = new LoadTask(); + Thread loadThread = new Thread(loadTask); + loadThread.start(); + + RemoveTask removeTask = new RemoveTask(); + Thread removeThread = new Thread(removeTask); + removeThread.start(); + + Thread.sleep(TEST_RUN_TIME_MS); + + saveTask.stop(); + loadTask.stop(); + removeTask.stop(); + + saveThread.join(); + loadThread.join(); + removeThread.join(); + + Assert.assertFalse("Exception during save", saveTask.getFailed()); + Assert.assertFalse("Exception during load", loadTask.getFailed()); + Assert.assertFalse("Exception during remove", removeTask.getFailed()); + } + + + private static final class SaveTask extends TaskBase { + + @Override + protected void doTask(Session session) throws Exception { + FILE_STORE.save(session); + } + + @Override + protected String getTaskName() { + return "save"; + } + } + + + private static final class LoadTask extends TaskBase { + + @Override + protected void doTask(Session session) throws Exception { + FILE_STORE.load(session.getId()); + } + + @Override + protected String getTaskName() { + return "load"; + } + } + + + private static final class RemoveTask extends TaskBase { + + @Override + protected void doTask(Session session) throws Exception { + FILE_STORE.remove(session.getId()); + } + + @Override + protected String getTaskName() { + return "remove"; + } + } + + + private abstract static class TaskBase implements Runnable { + + private volatile boolean stop = false; + private volatile boolean failed = false; + + @Override + public void run() { + while (!stop) { + for (Session session : SESSIONS) { + try { + doTask(session); + } catch (Exception e) { + System.out.println("Failed to " + getTaskName() + " session [" + session.getId() + "]"); + e.printStackTrace(System.out); + stop = true; + failed = true; + } + } + } + } + + public void stop() { + stop = true; + } + + public boolean getFailed() { + return failed; + } + + protected abstract void doTask(Session session) throws Exception; + protected abstract String getTaskName(); + } +} diff --git a/test/org/apache/catalina/session/TesterManager.java b/test/org/apache/catalina/session/TesterManager.java new file mode 100644 index 0000000000..f26fec377c --- /dev/null +++ b/test/org/apache/catalina/session/TesterManager.java @@ -0,0 +1,200 @@ +/* + * 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 org.apache.catalina.Context; +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.SessionIdGenerator; + +public class TesterManager implements Manager { + + private Context context; + + @Override + public Context getContext() { + return context; + } + + @Override + public void setContext(Context context) { + this.context = context; + } + + @Override + public SessionIdGenerator getSessionIdGenerator() { + return null; + } + + @Override + public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator) { + // NO-OP + } + + @Override + public long getSessionCounter() { + return 0; + } + + @Override + public int getMaxActive() { + return 0; + } + + @Override + public void setMaxActive(int maxActive) { + // NO-OP + } + + @Override + public int getActiveSessions() { + return 0; + } + + @Override + public long getExpiredSessions() { + return 0; + } + + @Override + public void setExpiredSessions(long expiredSessions) { + // NO-OP + } + + @Override + public int getRejectedSessions() { + return 0; + } + + @Override + public int getSessionMaxAliveTime() { + return 0; + } + + @Override + public void setSessionMaxAliveTime(int sessionMaxAliveTime) { + // NO-OP + } + + @Override + public int getSessionAverageAliveTime() { + return 0; + } + + @Override + public int getSessionCreateRate() { + return 0; + } + + @Override + public int getSessionExpireRate() { + return 0; + } + + @Override + public void add(Session session) { + // NO-OP + } + + @Override + public void addPropertyChangeListener(PropertyChangeListener listener) { + // NO-OP + } + + @Override + public void changeSessionId(Session session, String newId) { + // NO-OP + } + + @Override + public Session createEmptySession() { + return null; + } + + @Override + public Session createSession(String sessionId) { + return null; + } + + @Override + public Session findSession(String id) throws IOException { + return null; + } + + @Override + public Session[] findSessions() { + return null; + } + + @Override + public void load() throws ClassNotFoundException, IOException { + // NO-OP + } + + @Override + public void remove(Session session) { + // NO-OP + } + + @Override + public void remove(Session session, boolean update) { + // NO-OP + } + + @Override + public void removePropertyChangeListener(PropertyChangeListener listener) { + // NO-OP + } + + @Override + public void unload() throws IOException { + // NO-OP + } + + @Override + public void backgroundProcess() { + // NO-OP + } + + @Override + public boolean willAttributeDistribute(String name, Object value) { + return false; + } + + @Override + public void setNotifyBindingListenerOnUnchangedValue(boolean notifyBindingListenerOnUnchangedValue) { + // NO-OP + } + + @Override + public void setNotifyAttributeListenerOnUnchangedValue(boolean notifyAttributeListenerOnUnchangedValue) { + // NO-OP + } + + @Override + public void setSessionActivityCheck(boolean sessionActivityCheck) { + // NO-OP + } + + @Override + public void setSessionLastAccessAtStart(boolean sessionLastAccessAtStart) { + // NO-OP + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org