1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.test;
17
18 import org.apache.commons.io.FileUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.commons.lang.SystemUtils;
21 import org.junit.Assert;
22 import org.kuali.rice.core.api.config.property.Config;
23 import org.kuali.rice.core.api.config.property.ConfigContext;
24 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
25 import org.kuali.rice.kew.actionitem.ActionItem;
26 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
27 import org.kuali.rice.kew.api.WorkflowDocument;
28 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
29 import org.kuali.rice.kew.api.exception.WorkflowException;
30 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
31 import org.kuali.rice.kew.service.KEWServiceLocator;
32 import org.kuali.rice.kim.api.identity.IdentityService;
33 import org.kuali.rice.kim.api.identity.principal.Principal;
34 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
35 import org.springframework.jdbc.core.ConnectionCallback;
36 import org.springframework.jdbc.core.JdbcTemplate;
37 import org.springframework.jdbc.core.StatementCallback;
38 import org.springframework.transaction.PlatformTransactionManager;
39 import org.springframework.transaction.TransactionStatus;
40 import org.springframework.transaction.support.TransactionCallback;
41 import org.springframework.transaction.support.TransactionTemplate;
42
43 import javax.sql.DataSource;
44 import java.io.File;
45 import java.io.FileInputStream;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.sql.Connection;
49 import java.sql.ResultSet;
50 import java.sql.SQLException;
51 import java.sql.Statement;
52 import java.util.ArrayList;
53 import java.util.Collection;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Properties;
58 import java.util.Set;
59
60 import static org.junit.Assert.fail;
61
62
63
64
65
66 public final class TestUtilities {
67
68 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(TestUtilities.class);
69
70 private static final String TEST_TABLE_NAME = "EN_UNITTEST_T";
71 private static Thread exceptionThreader;
72
73 private TestUtilities() {
74 throw new UnsupportedOperationException("do not call");
75 }
76
77 public static InputStream loadResource(Class packageClass, String resourceName) {
78 return packageClass.getResourceAsStream(resourceName);
79 }
80
81 public static TransactionTemplate getTransactionTemplate() {
82 return (TransactionTemplate)
83 GlobalResourceLoader.getService(KEWServiceLocator.TRANSACTION_TEMPLATE);
84 }
85
86 public static void verifyTestEnvironment(DataSource dataSource) {
87 if (dataSource == null) {
88 Assert.fail("Could not locate the data source.");
89 }
90 JdbcTemplate template = new JdbcTemplate(dataSource);
91 template.execute(new ConnectionCallback() {
92 public Object doInConnection(Connection connection) throws SQLException {
93 ResultSet resultSet = connection.getMetaData().getTables(null, null, TEST_TABLE_NAME, null);
94 if (!resultSet.next()) {
95 LOG.error("No table named '"+TEST_TABLE_NAME+"' was found in the configured database. " +
96 "You are attempting to run tests against a non-test database!!!");
97 LOG.error("The test environment will not start up properly!!!");
98 Assert.fail("No table named '"+TEST_TABLE_NAME+"' was found in the configured database. " +
99 "You are attempting to run tests against a non-test database!!!");
100 }
101 return null;
102 }
103 });
104 }
105
106 public static void clearTables(final PlatformTransactionManager transactionManager, final DataSource dataSource, final String edenSchemaName, final List<String> dontClear) {
107 LOG.info("Clearing tables for schema " + edenSchemaName);
108 if (dataSource == null) {
109 Assert.fail("Null data source given");
110 }
111 if (edenSchemaName == null || edenSchemaName.equals("")) {
112 Assert.fail("Empty eden schema name given");
113 }
114 new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
115 public Object doInTransaction(TransactionStatus status) {
116 verifyTestEnvironment(dataSource);
117 JdbcTemplate template = new JdbcTemplate(dataSource);
118 return template.execute(new StatementCallback() {
119 public Object doInStatement(Statement statement) throws SQLException {
120 List<String> reEnableConstraints = new ArrayList<String>();
121 ResultSet resultSet = statement.getConnection().getMetaData().getTables(null, edenSchemaName, null, new String[] { "TABLE" });
122 while (resultSet.next()) {
123 String tableName = resultSet.getString("TABLE_NAME");
124 if (tableName.startsWith("EN_") && !dontClear.contains(tableName)) {
125 ResultSet keyResultSet = statement.getConnection().getMetaData().getExportedKeys(null, edenSchemaName, tableName);
126 while (keyResultSet.next()) {
127 String fkName = keyResultSet.getString("FK_NAME");
128 String fkTableName = keyResultSet.getString("FKTABLE_NAME");
129 statement.addBatch("ALTER TABLE "+fkTableName+" DISABLE CONSTRAINT "+fkName);
130 reEnableConstraints.add("ALTER TABLE "+fkTableName+" ENABLE CONSTRAINT "+fkName);
131 }
132 keyResultSet.close();
133 statement.addBatch("DELETE FROM "+tableName);
134 }
135 }
136 for (String constraint : reEnableConstraints) {
137 statement.addBatch(constraint);
138 }
139 statement.executeBatch();
140 resultSet.close();
141 return null;
142 }
143 });
144 }
145 });
146 LOG.info("Tables successfully cleared for schema " + edenSchemaName);
147 }
148
149 public static Set<String> createNodeInstanceNameSet(Collection nodeInstances) {
150 Set<String> nameSet = new HashSet<String>();
151 for (Iterator iterator = nodeInstances.iterator(); iterator.hasNext(); ) {
152 RouteNodeInstance nodeInstance = (RouteNodeInstance) iterator.next();
153 nameSet.add(nodeInstance.getName());
154 }
155 return nameSet;
156 }
157
158
159
160
161
162
163 public static void assertAtNode(String message, WorkflowDocument document, String nodeNameToAssert) {
164 Set<String> nodeNames = document.getNodeNames();
165 for (String nodeName : nodeNames) {
166 if (nodeNameToAssert.equals(nodeName)) {
167 return;
168 }
169 }
170 fail((org.apache.commons.lang.StringUtils.isEmpty(message) ? "" : message + ": ") + "Was [" + StringUtils.join(nodeNames, ", ") + "], Expected " + nodeNameToAssert);
171 }
172
173 public static void assertAtNode(WorkflowDocument document, String nodeName) throws WorkflowException {
174 assertAtNode("", document, nodeName);
175 }
176
177
178
179
180
181
182 public static void assertAtNodeNew(String message, org.kuali.rice.kew.api.WorkflowDocument document, String nodeName) throws WorkflowException {
183 Set<String> nodeNames = document.getNodeNames();
184 if (!nodeNames.contains(nodeName)) {
185 fail((org.apache.commons.lang.StringUtils.isEmpty(message) ? "" : message + ": ") + "Was [" + StringUtils.join(nodeNames, ", ") + "], Expected " + nodeName);
186 }
187 }
188
189 public static void assertAtNodeNew(org.kuali.rice.kew.api.WorkflowDocument document, String nodeName) throws WorkflowException {
190 assertAtNodeNew("", document, nodeName);
191 }
192
193
194
195
196 public static void assertInActionList(String principalId, String documentId) {
197 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
198 Assert.assertNotNull("Given principal id was invalid: " + principalId, principal);
199 Collection<ActionItem> actionList = KEWServiceLocator.getActionListService().findByPrincipalId(principalId);
200 for (Iterator iterator = actionList.iterator(); iterator.hasNext();) {
201 ActionItem actionItem = (ActionItem) iterator.next();
202 if (actionItem.getDocumentId().equals(documentId)) {
203 return;
204 }
205 }
206 Assert.fail("Could not locate an action item in the user's action list for the given document id.");
207 }
208
209
210
211
212 public static void assertNotInActionList(String principalId, String documentId) {
213 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalId);
214 Assert.assertNotNull("Given principal id was invalid: " + principalId, principal);
215 Collection actionList = KEWServiceLocator.getActionListService().findByPrincipalId(principalId);
216 for (Iterator iterator = actionList.iterator(); iterator.hasNext();) {
217 ActionItem actionItem = (ActionItem) iterator.next();
218 if (actionItem.getDocumentId().equals(documentId)) {
219 Assert.fail("Found an action item in the user's acton list for the given document id.");
220 }
221 }
222 }
223
224 public static void assertNumberOfPendingRequests(String documentId, int numberOfPendingRequests) {
225 List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
226 Assert.assertEquals("Wrong number of pending requests for document: " + documentId, numberOfPendingRequests, actionRequests.size());
227 }
228
229
230
231
232 public static void assertUserHasPendingRequest(String documentId, String principalName) throws WorkflowException {
233 String principalId = KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(principalName);
234 List actionRequests = KEWServiceLocator.getActionRequestService().findPendingByDoc(documentId);
235 boolean foundRequest = false;
236 for (Iterator iterator = actionRequests.iterator(); iterator.hasNext();) {
237 ActionRequestValue actionRequest = (ActionRequestValue) iterator.next();
238 if (actionRequest.isUserRequest() && actionRequest.getPrincipalId().equals(principalId)) {
239 foundRequest = true;
240 break;
241 } else if (actionRequest.isGroupRequest() &&
242 KimApiServiceLocator.getGroupService().isMemberOfGroup(principalId, actionRequest.getGroup().getId())) {
243 foundRequest = true;
244 break;
245 }
246 }
247 Assert.assertTrue("Could not locate pending request for the given user: " + principalId, foundRequest);
248 }
249
250
251
252
253
254
255
256
257 public static void assertApprovals(String docId, String[] users, boolean shouldHaveApproval) throws WorkflowException {
258 List<String> failedUsers = new ArrayList<String>();
259 IdentityService ims = KimApiServiceLocator.getIdentityService();
260 for (String user: users) {
261 WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(ims.getPrincipalByPrincipalName(user).getPrincipalId(), docId);
262 boolean appRqsted = doc.isApprovalRequested();
263 if (shouldHaveApproval != appRqsted) {
264 failedUsers.add(user);
265 }
266 LOG.info("User " + user + (appRqsted ? " HAS " : " HAS NO ") + "approval request");
267 }
268 for (String user: failedUsers) {
269 LOG.error("User " + user + (shouldHaveApproval ? " should have " : " should NOT have ") + " approval");
270 }
271 if (failedUsers.size() > 0) {
272 Assert.fail("Outstanding approvals are incorrect");
273 }
274 }
275
276 public static WorkflowDocument switchByPrincipalName(String principalName, WorkflowDocument document) throws WorkflowException {
277 return switchPrincipalId(KEWServiceLocator.getIdentityHelperService().getIdForPrincipalName(principalName), document);
278 }
279
280 public static WorkflowDocument switchPrincipalId(String principalId, WorkflowDocument document) throws WorkflowException {
281 return WorkflowDocumentFactory.loadDocument(principalId, document.getDocumentId());
282 }
283
284 public static void logActionRequests(String docId) {
285 List<ActionRequestValue> actionRequests = KEWServiceLocator.getActionRequestService().findAllActionRequestsByDocumentId(docId);
286 LOG.info("Current action requests:");
287 for (ActionRequestValue ar: actionRequests) {
288 LOG.info(ar);
289 }
290 }
291
292 public static JdbcTemplate getJdbcTemplate() {
293 JdbcTemplate jdbcTemplate = new JdbcTemplate(KEWServiceLocator.getDataSource());
294 jdbcTemplate.afterPropertiesSet();
295 return jdbcTemplate;
296 }
297
298
299
300
301
302
303
304
305
306 public static void waitForExceptionRouting() {
307 waitForExceptionRouting(5*60*1000);
308 }
309
310 public static void waitForExceptionRouting(long milliseconds) {
311 if (getExceptionThreader() == null) {
312 return;
313 }
314 try {
315 getExceptionThreader().join(milliseconds);
316 } catch (InterruptedException e) {
317 Assert.fail("This thread was interuppted while waiting for exception routing.");
318 }
319 if (getExceptionThreader().isAlive()) {
320 Assert.fail("Document was not put into exception routing within the specified amount of time " + milliseconds);
321 }
322 }
323
324 public static Thread getExceptionThreader() {
325 return exceptionThreader;
326 }
327
328 public static void setExceptionThreader(Thread exceptionThreader) {
329 TestUtilities.exceptionThreader = exceptionThreader;
330 }
331
332 private static final String DEFAULT_TEST_PLATFORM = "oracle";
333 private static final String BUILD_PROPERTIES = "build.properties";
334 private static final String TEST_PLATFORM = "test.platform";
335
336
337
338
339
340
341
342
343 public static String getTestPlatform() throws IOException {
344
345 File userBuildProperties = new File(SystemUtils.USER_HOME + "/" + BUILD_PROPERTIES);
346 if (userBuildProperties.isFile()) {
347 Properties properties = loadProperties(userBuildProperties);
348 if (properties.containsKey(TEST_PLATFORM)) {
349 return properties.getProperty(TEST_PLATFORM).toLowerCase();
350 }
351 }
352
353 File localBuildProperties = new File(BUILD_PROPERTIES);
354 if (localBuildProperties.isFile()) {
355 Properties properties = loadProperties(localBuildProperties);
356 if (properties.containsKey(TEST_PLATFORM)) {
357 return properties.getProperty(TEST_PLATFORM).toLowerCase();
358 }
359 }
360 return DEFAULT_TEST_PLATFORM.toLowerCase();
361 }
362
363
364
365
366
367
368 private static Properties loadProperties(File file) throws IOException {
369 Properties properties = new Properties();
370 FileInputStream fis = new FileInputStream(file);
371 try {
372 properties.load(fis);
373 } finally {
374 fis.close();
375 }
376 return properties;
377 }
378
379 public static File createTempDir() throws Exception {
380 File tmpFile = File.createTempFile("wfUnitTest", "");
381 Assert.assertTrue(tmpFile.delete());
382 File tmpDir = new File(new File(SystemUtils.JAVA_IO_TMPDIR), tmpFile.getName());
383 Assert.assertTrue(tmpDir.mkdir());
384 tmpDir.deleteOnExit();
385 return tmpDir;
386 }
387
388 public static File getPluginsDirectory() {
389 String directory = ConfigContext.getCurrentContextConfig().getProperty(Config.PLUGIN_DIR);
390 if (StringUtils.isNotBlank(directory)) {
391 return new File(directory);
392 }
393 return new File("./work/unit-test/plugins");
394 }
395
396 public static void initializePluginDirectories() throws Exception {
397 File pluginDir = getPluginsDirectory();
398 if (pluginDir.exists()) {
399 FileUtils.forceDelete(pluginDir);
400 }
401 FileUtils.forceMkdir(pluginDir);
402 FileUtils.forceDeleteOnExit(pluginDir);
403 }
404
405 public static void cleanupPluginDirectories() throws Exception {
406 FileUtils.deleteDirectory(getPluginsDirectory());
407 }
408
409
410
411
412
413
414
415 public static <T extends Throwable> T findExceptionInStack(Throwable topLevelException, Class<T> exceptionClass) {
416 Throwable t = topLevelException;
417 while (t != null) {
418 if (exceptionClass.isAssignableFrom(t.getClass())) return (T) t;
419 t = t.getCause();
420 }
421 return null;
422 }
423 }