1   package org.marketchangers.prayer.lucene;
2   
3   import java.io.IOException;
4   import java.text.SimpleDateFormat;
5   import java.util.Collection;
6   import java.util.Date;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.LinkedHashSet;
10  import java.util.Map;
11  import java.util.Set;
12  
13  import junit.framework.TestCase;
14  
15  import org.apache.lucene.analysis.Analyzer;
16  import org.apache.lucene.analysis.standard.StandardAnalyzer;
17  import org.apache.lucene.document.DateField;
18  import org.apache.lucene.document.Document;
19  import org.apache.lucene.index.IndexWriter;
20  import org.apache.lucene.index.Term;
21  import org.apache.lucene.queryParser.MultiFieldQueryParser;
22  import org.apache.lucene.search.BooleanClause;
23  import org.apache.lucene.search.BooleanQuery;
24  import org.apache.lucene.search.Query;
25  import org.apache.lucene.search.RangeQuery;
26  import org.apache.lucene.search.Searcher;
27  import org.apache.lucene.search.TermQuery;
28  import org.apache.lucene.store.Directory;
29  import org.apache.lucene.store.RAMDirectory;
30  import org.marketchangers.prayer.PrayerCategory;
31  import org.marketchangers.prayer.PrayerRequest;
32  import org.marketchangers.prayer.PrayerRequestQuery;
33  
34  /***
35   * @author <a href="mailto:mtodd@wc-group.com">Matthew Todd</a>
36   */
37  public class DefaultIndexProviderTest extends TestCase {
38  	private IndexProvider provider;
39  
40  	// ----------------------------------------------------------- SetUp Method
41  	public void setUp() throws IOException {
42  		Directory directory = new RAMDirectory();
43  		Analyzer analyzer = new StandardAnalyzer();
44  
45  		provider = new DefaultIndexProvider(directory, analyzer);
46  	}
47  
48  	// ----------------------------------------------------------- Test Methods
49  	public void testCanGetAWriter() throws IOException {
50  		assertNotNull(provider.getWriter());
51  	}
52  
53  	public void testBreaksWhenYouTryToGetASecondWriter() throws IOException {
54  		provider.getWriter();
55  		try {
56  			provider.getWriter();
57  		} catch (IOException ioe) {
58  			// expected to be here
59  		}
60  	}
61  
62  	public void testWorksIfCloseOneBeforeOpeningASecond() throws IOException {
63  		provider.getWriter().close();
64  		provider.getWriter();
65  	}
66  
67  	public void testCannotGetAReaderWithoutFirstGettingAWriter() {
68  		try {
69  			provider.getReader();
70  			fail("Should have to getWriter() before getReader().");
71  		} catch (Exception e) {
72  			// expect to be here
73  		}
74  	}
75  
76  	public void testCanGetAReaderAfterGettingAWriter() throws IOException {
77  		provider.getWriter();
78  		assertNotNull(provider.getReader());
79  	}
80  
81  	public void testBreaksWhenYouTryToGetASecondReader() throws IOException {
82  		provider.getWriter();
83  		provider.getReader();
84  		try {
85  			provider.getReader();
86  		} catch (IOException ioe) {
87  			// expected to be here
88  		}
89  	}
90  	public void testWorksIfCloseOneReaderBeforeOpeningASecond()
91  		throws IOException {
92  		provider.getWriter();
93  		provider.getReader().close();
94  		provider.getReader();
95  	}
96  
97  	public void testReusesTheSameDirectory() throws IOException {
98  		IndexWriter writer;
99  
100 		writer = provider.getWriter();
101 		writer.addDocument(new Document());
102 		writer.optimize();
103 		writer.close();
104 
105 		assertEquals(1, writer.docCount());
106 
107 		writer = provider.getWriter();
108 		writer.addDocument(new Document());
109 		writer.optimize();
110 		writer.close();
111 
112 		assertEquals(2, writer.docCount());
113 	}
114 
115 	public void testTranslatesRequestsIntoDocumentsAppropriately() {
116 		PrayerRequest request = buildDummyPrayerRequest(false);
117 		Document document = provider.translateToDocument(request);
118 
119 		assertEquals(request.getBackground(), document.get("background"));
120 		assertEquals(request.getCategory().getName(), document.get("category"));
121 		assertEquals(request.getContent(), document.get("content"));
122 		assertEquals(request.getId().toString(), document.get("id"));
123 		assertEquals(request.getStatus(), document.get("status"));
124 		assertEquals(request.getSubject(), document.get("subject"));
125 
126 		assertEquals(
127 			request.getEndDate(),
128 			DateField.stringToDate(document.get("endDate")));
129 		assertEquals(
130 			request.getRequestorUserId(),
131 			document.get("requestorUserId"));
132 		assertEquals(
133 			request.getStartDate(),
134 			DateField.stringToDate(document.get("startDate")));
135 	}
136 
137 	public void testTranslatesRequestsIntoDocumentsAppropriatelyWithNullCategory() {
138 		PrayerRequest request = buildDummyPrayerRequest(true);
139 		Document document = provider.translateToDocument(request);
140 
141 		assertEquals(request.getBackground(), document.get("background"));
142 		assertEquals("", document.get("category"));
143 		assertEquals(request.getContent(), document.get("content"));
144 		assertEquals(request.getId().toString(), document.get("id"));
145 		assertEquals(request.getStatus(), document.get("status"));
146 		assertEquals(request.getSubject(), document.get("subject"));
147 
148 		assertEquals(
149 			request.getEndDate(),
150 			DateField.stringToDate(document.get("endDate")));
151 		assertEquals(
152 			request.getRequestorUserId(),
153 			document.get("requestorUserId"));
154 		assertEquals(
155 			request.getStartDate(),
156 			DateField.stringToDate(document.get("startDate")));
157 	}
158 
159 	public void testTranslateKeepsTheAppropriateFieldsUntokenized() {
160 		Document document =
161 			provider.translateToDocument(buildDummyPrayerRequest(false));
162 
163 		assertFalse(document.getField("category").isTokenized());
164 		assertFalse(document.getField("endDate").isTokenized());
165 		assertFalse(document.getField("id").isTokenized());
166 		assertFalse(document.getField("requestorUserId").isTokenized());
167 		assertFalse(document.getField("startDate").isTokenized());
168 		assertFalse(document.getField("status").isTokenized());
169 	}
170 
171 	public void testTranslateToDocumentDoesNotFailForDefaultValues() {
172 		provider.translateToDocument(new PrayerRequest());
173 	}
174 
175 	public void testCanGetASearcherAfterGettingAWriter() throws IOException {
176 		provider.getWriter();
177 		assertNotNull(provider.getSearcher());
178 		assertTrue(provider.getSearcher() instanceof Searcher);
179 	}
180 
181 	public void testCannotGetASearcherBeforeYouveGottenAWriter() {
182 		try {
183 			provider.getSearcher();
184 			fail("Should have to getWriter() before getSearcher().");
185 		} catch (Exception e) {
186 			// expect to be here
187 		}
188 	}
189 
190 	public void testTranslateToQueryEmptyScenarios() {
191 		Query query =
192 			provider.translateToQuery(buildDummyEmptyPrayerRequestQuery());
193 		assertEquals(new BooleanQuery(), query);
194 	}
195 
196 	public void testTranslateToQueryDefault() throws java.text.ParseException {
197 		Date startDateVar = date("08-01-2004");
198 		Date endDateVar = date("08-08-2004");
199 
200 		BooleanClause categoryClause =
201 			new BooleanClause(categoryName("test category"), true, false);
202 
203 		BooleanClause endDateClause =
204 			new BooleanClause(endDate(endDateVar), true, false);
205 
206 		Set dummyHashSet = new LinkedHashSet();
207 		dummyHashSet.add("userid");
208 		BooleanClause requestorUserIdsClause =
209 			new BooleanClause(requestorUserIds(dummyHashSet), true, false);
210 
211 		BooleanClause searchTermsClause =
212 			new BooleanClause(searchTerms("random"), true, false);
213 
214 		BooleanClause startDateClause =
215 			new BooleanClause(startDate(startDateVar), true, false);
216 
217 		BooleanClause statusClause =
218 			new BooleanClause(status(PrayerRequest.OPEN), true, false);
219 
220 		PrayerRequestQuery requestQuery = buildDummyPrayerRequestQuery();
221 
222 		BooleanQuery query =
223 			(BooleanQuery) provider.translateToQuery(requestQuery);
224 		BooleanClause[] booleanClauses = query.getClauses();
225 		assertEquals(
226 			booleanClauseToString(categoryClause),
227 			booleanClauseToString(booleanClauses[0]));
228 		assertEquals(
229 			booleanClauseToString(endDateClause),
230 			booleanClauseToString(booleanClauses[1]));
231 		assertEquals(
232 			booleanClauseToString(requestorUserIdsClause),
233 			booleanClauseToString(booleanClauses[2]));
234 		assertEquals(
235 			booleanClauseToString(searchTermsClause),
236 			booleanClauseToString(booleanClauses[3]));
237 		assertEquals(
238 			booleanClauseToString(startDateClause),
239 			booleanClauseToString(booleanClauses[4]));
240 		assertEquals(
241 			booleanClauseToString(statusClause),
242 			booleanClauseToString(booleanClauses[5]));
243 	}
244 
245 	public void testTranslatePrayerRequestToQuery() {
246 		PrayerRequest request = new PrayerRequest();
247 		Date startDate = new Date();
248 		Date endDate = new Date();
249 		PrayerCategory category = new PrayerCategory();
250 		category.setId(new Integer(11));
251 		category.setName("test");
252 		BooleanQuery bq = new BooleanQuery();
253 		bq.add(new TermQuery(new Term("category", "test")), true, false);
254 		bq.add(
255 			new RangeQuery(
256 				null,
257 				new Term("endDate", DateField.dateToString(endDate)),
258 				true),
259 			true,
260 			false);
261 		bq.add(new TermQuery(new Term("requestorUserId", "jniu")), true, false);
262 		bq.add(searchTerms("this is a test"), true, false);
263 		bq.add(
264 			new RangeQuery(
265 				new Term("startDate", DateField.dateToString(startDate)),
266 				null,
267 				true),
268 			true,
269 			false);
270 
271 		request.setCategory(category);
272 		request.setContent("this is a test");
273 		request.setStartDate(startDate);
274 		request.setEndDate(endDate);
275 		request.setRequestorUserId("jniu");
276 		Query query = provider.translateToQuery(request);
277 
278 		assertEquals(bq.toString(), query.toString());
279 	}
280 
281 	public void testTranslatePrayerRequestToQueryCanHandleNullCategory() {
282 		PrayerRequest request = new PrayerRequest();
283 		Date startDate = new Date();
284 		Date endDate = new Date();
285 		PrayerCategory category = null;
286 		BooleanQuery bq = new BooleanQuery();
287 		bq.add(
288 			new RangeQuery(
289 				null,
290 				new Term("endDate", DateField.dateToString(endDate)),
291 				true),
292 			true,
293 			false);
294 		bq.add(new TermQuery(new Term("requestorUserId", "jniu")), true, false);
295 		bq.add(searchTerms("this is a test"), true, false);
296 		bq.add(
297 			new RangeQuery(
298 				new Term("startDate", DateField.dateToString(startDate)),
299 				null,
300 				true),
301 			true,
302 			false);
303 
304 		request.setContent("this is a test");
305 		request.setStartDate(startDate);
306 		request.setEndDate(endDate);
307 		request.setRequestorUserId("jniu");
308 		Query query = provider.translateToQuery(request);
309 
310 		assertEquals(bq.toString(), query.toString());
311 	}
312 
313 	// ---------------------------------------------private method	
314 	private Query all() {
315 		return new TermQuery(new Term("catchAll", "catchAll"));
316 	}
317 
318 	private String[] array(String value) {
319 		return new String[] { value };
320 	}
321 
322 	private String booleanClauseToString(BooleanClause clause) {
323 		return clause.query.toString();
324 	}
325 
326 	private PrayerRequestQuery buildDummyEmptyPrayerRequestQuery() {
327 		Map map = new HashMap();
328 		return new PrayerRequestQuery(map);
329 	}
330 
331 	private PrayerRequest buildDummyPrayerRequest(boolean nullCategory) {
332 		PrayerCategory category;
333 		if (nullCategory) {
334 			category = null;
335 		} else {
336 			category = new PrayerCategory();
337 			category.setName("foo");
338 		}
339 
340 		PrayerRequest request = new PrayerRequest();
341 		request.setBackground("foo");
342 		request.setCategory(category);
343 		request.setContent("foo");
344 		request.setEndDate(new Date());
345 		request.setId(new Integer(42));
346 		request.setRequestorUserId("foo");
347 		request.setStartDate(new Date());
348 		request.setStatus("foo");
349 		request.setSubject("foo");
350 
351 		return request;
352 	}
353 
354 	private PrayerRequestQuery buildDummyPrayerRequestQuery() {
355 		Map map = new HashMap();
356 		map.put("categoryName", array("test category"));
357 		map.put("endDate", array("08-08-2004"));
358 		map.put("organizationName", array("new org"));
359 		map.put("requestorUserId", array("userid"));
360 		map.put("searchTerms", array("random"));
361 		map.put("startDate", array("08-01-2004"));
362 		map.put("status", array(PrayerRequest.OPEN));
363 		return new PrayerRequestQuery(map);
364 	}
365 
366 	private Query categoryName(String categoryName) {
367 		return new TermQuery(new Term("category", categoryName));
368 	}
369 
370 	private Date date(String value) throws java.text.ParseException {
371 		return new SimpleDateFormat("MM-dd-yyyy").parse(value);
372 	}
373 
374 	private Query endDate(Date date) {
375 		Term upperTerm = new Term("endDate", DateField.dateToString(date));
376 		return new RangeQuery(null, upperTerm, true);
377 	}
378 
379 	private Query requestorUserId(String requestorUserId) {
380 		return new TermQuery(new Term("requestorUserId", requestorUserId));
381 	}
382 
383 	private Query requestorUserIds(Collection requestors) {
384 		BooleanQuery query = new BooleanQuery();
385 
386 		Iterator requestorUserIds = requestors.iterator();
387 		while (requestorUserIds.hasNext()) {
388 			String requestorUserId = (String) requestorUserIds.next();
389 			query.add(requestorUserId(requestorUserId), false, false);
390 		}
391 		return query;
392 	}
393 
394 	private Query searchTerms(String searchTerms) {
395 		String[] fields = { "background", "content", "subject" };
396 
397 		try {
398 			return MultiFieldQueryParser.parse(
399 				searchTerms,
400 				fields,
401 				new StandardAnalyzer());
402 		} catch (Exception pe) {
403 			return all();
404 		}
405 	}
406 
407 	private Query startDate(Date date) {
408 		Term lowerTerm = new Term("startDate", DateField.dateToString(date));
409 		return new RangeQuery(lowerTerm, null, true);
410 	}
411 
412 	private Query status(String status) {
413 		return new TermQuery(new Term("status", status));
414 	}
415 
416 }