View Javadoc

1   /***
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package net.sf.jpam;
17  
18  import junit.framework.TestCase;
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  /***
26   * Performs tests on the Pam class.
27   * <p/>
28   * Create the following users before running tests:
29   * <ol>
30   * <li>user test with password test01
31   * <li>user test2 with password test02
32   * </ol>
33   * Linux systems may need /etc/shadow to be made readable by the user
34   *
35   * @author <a href="mailto:gregluck@users.sourceforge.net">Greg Luck</a>
36   * @version $Id: AbstractPamTest.java 2 2007-01-02 00:13:50Z gregluck $
37   */
38  public class AbstractPamTest extends TestCase {
39      private static final Log LOG = LogFactory.getLog(AbstractPamTest.class.getName());
40      /***
41       * user 1 name
42       */
43      protected String user1Name = "test";
44      /***
45       * user 1 credentials
46       */
47      protected String user1Credentials = "test01";
48      /***
49       * user 1 bad credentials
50       */
51      protected String user1BadCredentials = "test01bad";
52      /***
53       * user 2 name
54       */
55      protected String user2Name = "test2";
56      /***
57       * user 2 credentials
58       */
59      protected String user2Credentials = "test02";
60      /***
61       * user 2 bad credentials
62       */
63      protected String user2BadCredentials = "test02bad";
64  
65  
66      /***
67       * An empty test to keep IntelliJ Test Runner happy
68       */
69      public void testPlaceHolder() {
70          //
71      }
72  
73  
74      /***
75       * Multi-threaded PAM test.
76       */
77      public void concurrentPamStressTest(final Pam pam, final PamReturnValue[] expectedReturnValues) throws InterruptedException {
78          final long startingSize = measureMemoryUse();
79  
80          //Create a list of threads
81          final List executables = new ArrayList();
82  
83          //Add threads for user1 authentication
84          for (int i = 0; i < 15; i++) {
85              final Executable executable = new Executable() {
86                  public void execute() throws Exception {
87                      LOG.info("Running 1");
88                      PamReturnValue value = pam.authenticate(user1Name, user1Credentials);
89                      checkReturnValue(expectedReturnValues, value);
90                  }
91              };
92              executables.add(executable);
93          }
94  
95          //Add threads for user2 authentication
96          for (int i = 0; i < 15; i++) {
97              final Executable executable1 = new Executable() {
98                  public void execute() throws Exception {
99                      LOG.info("Running 2");
100                     PamReturnValue value = pam.authenticate(user2Name, user2Credentials);
101                     checkReturnValue(expectedReturnValues, value);
102                 }
103             };
104             executables.add(executable1);
105         }
106 
107         List errors = runThreads(executables);
108 
109         long finishingSize = measureMemoryUse();
110         long difference = finishingSize - startingSize;
111         LOG.info("Memory Change is: " + difference);
112 
113         // Throw any error that happened
114         if (errors.size() != 0) {
115             LOG.error("" + errors.size() + " failures in run.");
116             for (int i = 0; i < errors.size(); i++) {
117                 Throwable throwable = (Throwable) errors.get(i);
118                 LOG.error("Error " + i + ": " + throwable);
119             }
120             assertEquals("Errors occurred during run", 0, errors.size());
121         }
122     }
123 
124     private void checkReturnValue(PamReturnValue[] expectedReturnValues, PamReturnValue pamReturnValue)
125             throws PamException {
126         boolean match = false;
127         for (int i = 0; i < expectedReturnValues.length; i++) {
128             PamReturnValue returnValue = expectedReturnValues[i];
129             if (expectedReturnValues[i].equals(pamReturnValue)) {
130                 match = true;
131             }
132         }
133         StringBuffer expected = new StringBuffer();
134         for (int i = 0; i < expectedReturnValues.length; i++) {
135             PamReturnValue expectedReturnValue = expectedReturnValues[i];
136             expected.append("\"").append(expectedReturnValue).append("\"").append(' ');
137         }
138 
139         if (!match) {
140             throw new PamException("Test failure. Return expected one of " + expected
141                     + " Actual return value was: " + pamReturnValue);
142         }
143     }
144 
145     /***
146      * Measures the memory use. Because Garbage Collection is done, memory should
147      * not increase.
148      *
149      * @return the memory increase/- decrease in bytes
150      * @throws InterruptedException
151      */
152     protected long measureMemoryUse() throws InterruptedException {
153         System.gc();
154         Thread.sleep(3000);
155         System.gc();
156         long startingSize = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
157         return startingSize;
158     }
159 
160 
161     /***
162      * Runs a set of threads, for a fixed amount of time.
163      */
164     protected List runThreads(final List executables) throws InterruptedException {
165         final Counter counter = new Counter();
166         final long endTime = System.currentTimeMillis() + 10000;
167         final List errors = new ArrayList();
168 
169         // Spin up the threads
170         final Thread[] threads = new Thread[executables.size()];
171         for (int i = 0; i < threads.length; i++) {
172             final Executable executable = (Executable) executables.get(i);
173             threads[i] = new Thread() {
174                 public void run() {
175                     try {
176                         // Run the thread until the given end time
177                         while (System.currentTimeMillis() < endTime) {
178                             executable.execute();
179                             counter.increment();
180                         }
181                     } catch (Throwable t) {
182                         // Hang on to any errors
183                         errors.add(t);
184                     }
185                 }
186             };
187             threads[i].start();
188         }
189 
190         // Wait for the threads to finish
191         for (int i = 0; i < threads.length; i++) {
192             threads[i].join();
193         }
194         LOG.info("Number of executes run: " + counter.counter);
195         return errors;
196     }
197 
198     /***
199      * A runnable, that can throw an exception.
200      */
201     protected interface Executable {
202 
203         /***
204          * Executes this object
205          */
206         void execute() throws Exception;
207     }
208 
209     /***
210      * Counts the tests
211      */
212     protected class Counter {
213         private int counter;
214 
215         private synchronized void increment() {
216             counter++;
217         }
218     }
219 }