1 /* ====================================================================
2 * License:
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. The end-user documentation included with the redistribution,
17 * if any, must include the following acknowledgment:
18 * "This product includes software developed by
19 * Robert Half International (http://www.rhi.com/)."
20 * Alternately, this acknowledgment may appear in the software itself,
21 * if and wherever such third-party acknowledgments normally appear.
22 *
23 * 4. The names "Parc", "RHI", and "Robert Half International" must
24 * not be used to endorse or promote products derived from this
25 * software without prior written permission. For written
26 * permission, please contact pete.mckinstry@rhi.com.
27 *
28 * 5. Products derived from this software may not be called "PARC",
29 * nor may "PARC" appear in their name, without prior written
30 * permission of Robert Half International.
31 *
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
36 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
39 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
42 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 * ====================================================================
45 *
46 */
47 package com.rhi.architecture.parc.adapter;
48
49 import com.rhi.architecture.batch.AuditAgent;
50 import com.rhi.architecture.batch.TestAuditAgent;
51 import com.rhi.architecture.config.ConfigFacility;
52 import com.rhi.architecture.parc.ArrayListQueue;
53 import com.rhi.architecture.parc.Channel;
54 import com.rhi.architecture.parc.ExceptionHandler;
55 import com.rhi.architecture.parc.PARCTest;
56 import com.rhi.architecture.parc.TestError;
57 import com.rhi.architecture.parc.TestRecord;
58 import com.rhi.architecture.resource.ResourceContext;
59 import com.rhi.architecture.xa.Transaction;
60
61 import java.util.ArrayList;
62 import java.util.Collection;
63 import java.util.List;
64 import java.util.Properties;
65
66 import junit.framework.Test;
67 import junit.framework.TestSuite;
68
69 /***
70 * OutputAdapterTest.java
71 *
72 * @author <a href="mailto:pete.mckinstry@rhi.com">Pete McKinstry</a>
73 * @copyright 2002, Robert Half International, All rights reserved.
74 *
75 * @version 1.0
76 */
77 public class OutputAdapterTest extends PARCTest {
78
79 private TestOutputAdapter oa;
80 private Channel valid;
81 private Channel error;
82 private ExceptionHandler handler;
83 private AuditAgent auditAgent;
84
85 /***
86 * Constructor for OutputAdapterTest.
87 * @param name
88 */
89 public OutputAdapterTest(String name) {
90 super(name);
91 }
92
93 /***
94 * Allow subclasses to add extra params. Default impl provided.
95 * @param p
96 * @return
97 */
98 public Properties doGetProperties(Properties p) {
99 p.setProperty(
100 Transaction.TYPE_KEY,
101 "com.rhi.architecture.xa.TestTransaction");
102 p.setProperty("AbstractOutputAdapter.MaxSleep", "100");
103 super.setLoadDriver(false);
104
105 return p;
106 }
107
108 /***
109 * setup
110 * @throws Exception
111 */
112 protected void setUp() throws Exception {
113 super.setUp();
114 oa = new TestOutputAdapter();
115 valid = new ArrayListQueue();
116 error = new ArrayListQueue();
117 handler = new ExceptionHandler();
118 auditAgent = new TestAuditAgent();
119
120 ResourceContext ctx = new ResourceContext();
121 ConfigFacility config = (ConfigFacility) ctx.lookup(ConfigFacility.KEY);
122 Properties p = config.getProperties();
123
124 oa.init(p);
125 oa.setValidChannel(valid);
126 oa.setErrorChannel(error);
127 oa.setExceptionHandler(handler);
128 oa.setAuditAgent(auditAgent);
129 }
130
131 /***
132 * tear down
133 * @throws Exception
134 */
135 protected void tearDown() throws Exception {
136 super.tearDown();
137 oa.cleanup();
138 }
139
140 /***
141 * Test the error handling
142 *
143 * Set the valid channel to null, thus causing the output
144 * adapter to fail w/ a fatal runtime exception. The run()
145 * method should detect this error & instead of crashing,
146 * signal the error handler.
147 *
148 * @throws Exception
149 * @since 1,1
150 */
151 public void testExceptionThrown() throws Exception {
152 this.oa.setValidChannel(null);
153
154 // just immediately after processing records.
155 this.oa.markComplete();
156
157 Thread oaThread = new Thread(this.oa);
158
159 oaThread.start();
160
161 while (oaThread.isAlive()) {
162 try {
163 Thread.sleep(100);
164 }
165 catch (InterruptedException e) {
166 // ignore
167 }
168 }
169
170 assertTrue(
171 "exception not caught by OutputAdapter.",
172 handler.hasError() == true);
173 }
174
175 /***
176 * Simple test
177 * Push record into inbound channel before starting OA,
178 * then check that record comes out the other end.
179 *
180 * @throws Exception
181 * @since 1,1
182 */
183 public void testOneRecord() throws Exception {
184 List records = new ArrayList();
185
186 records.add(new TestRecord());
187 this.valid.push(records);
188
189 // just immediately after processing records.
190 this.oa.markComplete();
191
192 Thread oaThread = new Thread(this.oa);
193
194 oaThread.start();
195
196 while (oaThread.isAlive()) {
197 try {
198 Thread.sleep(100);
199 }
200 catch (InterruptedException e) {
201 // ignore
202 }
203 }
204
205 assertTrue(
206 "exception thrown by OutputAdapter.",
207 handler.hasError() == false);
208 records = oa.getValidRecords();
209 assertTrue("valid record size wrong.", records.size() == 1);
210 records = oa.getErrorRecords();
211 assertTrue("error record size wrong.", records.size() == 0);
212 }
213
214 /***
215 * Test of non-thread version to ensure backward compatibility.
216 *
217 * @throws Exception
218 * @since 1,1
219 */
220 public void testNonThreadOutputAdapter() throws Exception {
221 List records = new ArrayList();
222
223 records.add(new TestRecord());
224 this.valid.push(records);
225
226 // just immediately after processing records.
227 this.oa.markComplete();
228
229 this.oa.run();
230
231 assertTrue(
232 "exception thrown by OutputAdapter.",
233 handler.hasError() == false);
234 records = oa.getValidRecords();
235 assertTrue("valid record size wrong.", records.size() == 1);
236 records = oa.getErrorRecords();
237 assertTrue("error record size wrong.", records.size() == 0);
238 }
239
240 /***
241 * Start the output adapter first, then push some records into
242 * the channel multiple times to simulate a multi-batch interface
243 * After both batches are pushed, mark the OA complete & ensure
244 * that it shuts down properly (w/ all the records accounted for.
245 *
246 * @throws Exception
247 * @since 1,1
248 */
249 public void testNormalScenario() throws Exception {
250 Thread oaThread = new Thread(this.oa);
251
252 oaThread.start();
253
254 // wait for a bit.
255 try {
256 Thread.sleep(1000);
257 }
258 catch (InterruptedException e) {
259 // ignore
260 }
261
262 // now, push some records into the channel.
263 List records1 = new ArrayList();
264
265 records1.add(new TestRecord());
266 records1.add(new TestRecord());
267 records1.add(new TestRecord());
268 this.valid.push(records1);
269
270 // and push some more.
271 List records2 = new ArrayList();
272
273 records2.add(new TestRecord());
274 records2.add(new TestRecord());
275 this.valid.push(records2);
276
277 // after it's done w/ these 5, exit.
278 this.oa.markComplete();
279
280 while (oaThread.isAlive()) {
281 try {
282 Thread.sleep(100);
283 }
284 catch (InterruptedException e) {
285 // ignore
286 }
287 }
288
289 assertTrue(
290 "exception not caught by OutputAdapter.",
291 handler.hasError() == false);
292
293 Collection records = oa.getValidRecords();
294
295 assertTrue("valid record size wrong.", records.size() == 5);
296 records = oa.getErrorRecords();
297 assertTrue("error record size wrong.", records.size() == 0);
298 }
299
300 /***
301 * Test of wait/notify logic.
302 *
303 * Start the output adapter first, then push some records into
304 * the channel multiple times to simulate a multi-batch interface
305 * After both batches are pushed, mark the OA complete & ensure
306 * that it shuts down properly (w/ all the records accounted for.
307 *
308 * @throws Exception
309 * @since 1,1
310 */
311 public void testOutputAdapterNotifyWaitCycle() throws Exception {
312 Thread oaThread = new Thread(this.oa);
313
314 oaThread.start();
315
316 // wait for a bit, forcing the OA to sleep (no records yet)
317 try {
318 Thread.sleep(250);
319 }
320 catch (InterruptedException e) {
321 // ignore
322 }
323
324 // Batch 1
325 List records1 = new ArrayList();
326
327 records1.add(new TestRecord());
328 records1.add(new TestRecord());
329 records1.add(new TestRecord());
330 this.valid.push(records1);
331
332 // wait for a bit, forcing the OA to sleep. 1 cycle, then empty cycle.
333 try {
334 Thread.sleep(1000);
335 }
336 catch (InterruptedException e) {
337 // ignore
338 }
339
340 // Batch 2
341 List records2 = new ArrayList();
342
343 records2.add(new TestRecord());
344 records2.add(new TestRecord());
345 this.valid.push(records2);
346
347 // after it's done w/ these 5, exit.
348 this.oa.markComplete();
349
350 while (oaThread.isAlive()) {
351 try {
352 Thread.sleep(100);
353 }
354 catch (InterruptedException e) {
355 // ignore
356 }
357 }
358
359 int writeCount = ((TestOutputAdapter)this.oa).getWriteCount();
360 System.out.println("write called " + writeCount + " times");
361 assertTrue( "incorrect number of batches. wait/notify logic broken. " +
362 "write() called " + writeCount,
363 writeCount<15);
364
365 int handleValidCount = ((TestOutputAdapter)this.oa).getHandleValidCount();
366 System.out.println("handleValid called " + handleValidCount + " times");
367 assertTrue( "wait/notify logic broken. " +
368 "handleValid called " + handleValidCount + " times",
369 handleValidCount==2);
370
371
372 assertTrue( "exception not caught by OutputAdapter.",
373 handler.hasError() == false);
374
375 Collection records = oa.getValidRecords();
376
377 assertTrue("valid record size wrong.", records.size() == 5);
378 records = oa.getErrorRecords();
379 assertTrue("error record size wrong.", records.size() == 0);
380 }
381
382 /***
383 * Add errored records to error channel & make sure they
384 * are propertly accounted for.
385 *
386 * @throws Exception
387 * @since 1,1
388 */
389 public void testErrorChannel() throws Exception {
390 List records = new ArrayList();
391 TestRecord r = new TestRecord();
392
393 r.addError(new TestError());
394 records.add(r);
395 records.add(r);
396 this.error.push(records);
397
398 // just immediately after processing records.
399 this.oa.markComplete();
400
401 Thread oaThread = new Thread(this.oa);
402
403 oaThread.start();
404
405 while (oaThread.isAlive()) {
406 try {
407 Thread.sleep(100);
408 }
409 catch (InterruptedException e) {
410 // ignore
411 }
412 }
413
414 assertTrue(
415 "exception thrown by OutputAdapter.",
416 handler.hasError() == false);
417 records = oa.getValidRecords();
418 assertTrue("valid record size wrong.", records.size() == 0);
419 records = oa.getErrorRecords();
420 assertTrue("error record size wrong.", records.size() == 2);
421 }
422
423 /***
424 * Add errored records to valid channel & make sure they
425 * are propertly accounted for.
426 *
427 * @throws Exception
428 * @since 1,1
429 */
430 public void testErrorsInValidChannel() throws Exception {
431 List records = new ArrayList();
432 TestRecord r = new TestRecord();
433
434 r.addError(new TestError());
435 records.add(r);
436 records.add(r);
437 this.valid.push(records);
438
439 // just immediately after processing records.
440 this.oa.markComplete();
441
442 Thread oaThread = new Thread(this.oa);
443
444 oaThread.start();
445
446 while (oaThread.isAlive()) {
447 try {
448 Thread.sleep(100);
449 }
450 catch (InterruptedException e) {
451 // ignore
452 }
453 }
454
455 assertTrue(
456 "exception thrown by OutputAdapter.",
457 handler.hasError() == false);
458 records = oa.getValidRecords();
459 assertTrue("valid record size wrong.", records.size() == 0);
460 records = oa.getErrorRecords();
461 assertTrue("error record size wrong.", records.size() == 2);
462 }
463
464 /***
465 * suite of all tests
466 * @return Test
467 */
468 public static Test suite() {
469 return new TestSuite(OutputAdapterTest.class);
470 }
471
472 }
This page was automatically generated by Maven