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
81 final List executables = new ArrayList();
82
83
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
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
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
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
177 while (System.currentTimeMillis() < endTime) {
178 executable.execute();
179 counter.increment();
180 }
181 } catch (Throwable t) {
182
183 errors.add(t);
184 }
185 }
186 };
187 threads[i].start();
188 }
189
190
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 }