001// Copyright 2009 by Basil Vandegriend. All rights reserved. 002 003package com.basilv.examples.concurrency; 004 005import static org.junit.Assert.*; 006 007import java.util.*; 008import java.util.concurrent.atomic.AtomicReference; 009 010import org.junit.*; 011 012public class DateProcessorMultiThreadedTest 013{ 014 015 @Before 016 public void setUp() { 017 DateProcessor.setInstanceForTesting(null); 018 } 019 020 @Test 021 public void multithreadedExecutionOneThread() { 022 verifyMultiThreadedExecution(1); // Should always pass 023 } 024 025 @Test 026 public void multithreadedExecutionFewThreads() { 027 verifyMultiThreadedExecution(3); // Always seems to pass 028 } 029 030 @Test 031 public void multithreadedExecutionManyThreads() { 032 boolean successful = false; 033 try { 034 // 500 always seems to fail given my hardware/software platform, even when 035 // entire Examples suite is executed. Smaller numbers inconsistently fail, especially 036 // when entire suite is executed. 037 verifyMultiThreadedExecution(500); 038 successful = true; 039 } catch (AssertionError e) { 040 // Expected case. 041 successful = false; 042 System.err.print("Expected failure due to:" + e.getMessage()); 043 } 044 if (successful) { 045 fail("Expected exception"); 046 } 047 } 048 049 private void verifyMultiThreadedExecution(int totalExecutions) { 050 int totalValid = totalExecutions / 2; 051 List<DateProcessorThread> threads = new ArrayList<DateProcessorThread>(totalExecutions); 052 053 // Execute threads 054 for (int i = 0; i < totalValid; i++) { 055 DateProcessorThread thread = createAndStartThread("2009-11-25", true); 056 threads.add(thread); 057 058 } 059 for (int i = 0; i < totalExecutions - totalValid; i++) { 060 DateProcessorThread thread = createAndStartThread("foo", false); 061 threads.add(thread); 062 } 063 064 // Wait for all threads to be finished 065 for (Thread thread : threads) { 066 try { 067 thread.join(); 068 } catch (InterruptedException e) { 069 // Ignore for testing. 070 } 071 } 072 073 // Verify totals 074 assertEquals("Total execution count", totalExecutions, DateProcessor.getInstance().getDatesProcessedCount()); 075 assertEquals("Total valid count", totalValid, DateProcessor.getInstance().getDatesValidCount()); 076 077 // Verify individual results 078 for (DateProcessorThread thread : threads) { 079 thread.verifyResults(); 080 } 081 } 082 083 private DateProcessorThread createAndStartThread(String input, boolean expectValid) { 084 DateProcessorThread thread = new DateProcessorThread(input, expectValid); 085 thread.start(); 086 return thread; 087 } 088 089 private static class DateProcessorThread extends Thread { 090 091 private final String input; 092 private final boolean expectValid; 093 private AtomicReference<Date> resultRef = new AtomicReference<Date>(); 094 095 public DateProcessorThread(String input, boolean expectValid) { 096 this.input = input; 097 this.expectValid = expectValid; 098 } 099 100 @Override 101 public void run() { 102 Date date = DateProcessor.getInstance().processDate(input); 103 resultRef.set(date); 104 } 105 106 public void verifyResults() { 107 Date result = resultRef.get(); 108 if (expectValid) { 109 assertNotNull(result); 110 } else { 111 assertNull(result); 112 } 113 } 114 115 } 116}