| /* |
| * 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 TestFileStoreConcurrency { |
| |
| 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()); |
| |
| System.out.println("Looped over sessions [" + saveTask.getLoopCount() + "] times calling save()"); |
| System.out.println("Looped over sessions [" + loadTask.getLoopCount() + "] times calling load()"); |
| System.out.println("Looped over sessions [" + removeTask.getLoopCount() + "] times calling remove()"); |
| } |
| |
| |
| 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; |
| private volatile int loopCount = 0; |
| |
| @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; |
| } |
| } |
| loopCount++; |
| } |
| } |
| |
| public void stop() { |
| stop = true; |
| } |
| |
| public boolean getFailed() { |
| return failed; |
| } |
| |
| public int getLoopCount() { |
| return loopCount; |
| } |
| |
| protected abstract void doTask(Session session) throws Exception; |
| protected abstract String getTaskName(); |
| } |
| } |