1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.index;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.io.PrintWriter;
26 import java.io.StringWriter;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.Files;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.apache.lucene.index.Term;
37 import org.apache.lucene.search.BooleanClause.Occur;
38 import org.apache.lucene.search.BooleanQuery;
39 import org.apache.lucene.search.IndexSearcher;
40 import org.apache.lucene.search.Query;
41 import org.apache.lucene.search.TermQuery;
42 import org.apache.lucene.search.WildcardQuery;
43 import org.apache.lucene.store.ByteBuffersDirectory;
44 import org.apache.lucene.store.Directory;
45 import org.apache.maven.index.context.IndexCreator;
46 import org.apache.maven.index.context.IndexingContext;
47 import org.apache.maven.index.context.MergedIndexingContext;
48 import org.apache.maven.index.context.StaticContextMemberProvider;
49 import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
50 import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator;
51 import org.apache.maven.index.packer.IndexPacker;
52 import org.apache.maven.index.packer.IndexPackingRequest;
53 import org.apache.maven.index.search.grouping.GAGrouping;
54 import org.apache.maven.index.updater.DefaultIndexUpdater;
55 import org.apache.maven.index.updater.IndexUpdateRequest;
56 import org.apache.maven.index.updater.IndexUpdater;
57 import org.codehaus.plexus.util.StringUtils;
58 import org.junit.Test;
59
60 import static org.hamcrest.CoreMatchers.is;
61 import static org.junit.Assert.assertEquals;
62 import static org.junit.Assert.assertNotNull;
63 import static org.junit.Assert.assertNull;
64 import static org.junit.Assert.assertThat;
65 import static org.junit.Assert.assertTrue;
66
67
68 public class NexusIndexerTest extends AbstractIndexCreatorHelper {
69 private IndexingContext context;
70
71 @Test
72 public void testSingleQuery() throws Exception {
73 NexusIndexer indexer = lookup(NexusIndexer.class);
74
75 File indexDir = super.getDirectory("index/test");
76 super.deleteDirectory(indexDir);
77
78 File repo = new File(getBasedir(), "src/test/repo");
79
80 context = indexer.addIndexingContext("test", "test", repo, indexDir, null, null, DEFAULT_CREATORS);
81 indexer.scan(context);
82
83 Query q;
84
85
86 q = indexer.constructQuery(MAVEN.NAME, "Some artifact name from Pom", SearchType.SCORED);
87 assertThat(q.toString(), is("(+n:some +n:artifact +n:name +n:from +n:Pom*) n:\"some artifact name from pom\""));
88 }
89
90 @Test
91 public void testQueryCreatorNG() throws Exception {
92 NexusIndexer indexer = prepare();
93
94 Query q;
95
96
97 q = indexer.constructQuery(MAVEN.GROUP_ID, "commons-loggin*", SearchType.EXACT);
98
99
100 assertEquals(MinimalArtifactInfoIndexCreator.FLD_GROUP_ID_KW.getKey() + ":commons-loggin*", q.toString());
101
102
103 q = indexer.constructQuery(MAVEN.GROUP_ID, "commons-loggin*", SearchType.SCORED);
104
105
106 assertEquals(
107 "g:commons-loggin* ((+groupId:commons +groupId:loggin*) groupId:\"commons loggin\")", q.toString());
108
109
110 q = indexer.constructQuery(MAVEN.GROUP_ID, "commons-logging", SearchType.EXACT);
111
112 assertEquals(MinimalArtifactInfoIndexCreator.FLD_GROUP_ID_KW.getKey() + ":commons-logging", q.toString());
113
114
115 q = indexer.constructQuery(MAVEN.PACKAGING, "maven-archetype", SearchType.EXACT);
116
117 assertEquals(MinimalArtifactInfoIndexCreator.FLD_PACKAGING.getKey() + ":maven-archetype", q.toString());
118
119
120 q = indexer.constructQuery(MAVEN.PACKAGING, "maven-archetype", SearchType.SCORED);
121
122 assertEquals("p:maven-archetype (p:maven-archetype*)^0.8", q.toString());
123
124
125 q = indexer.constructQuery(MAVEN.ARTIFACT_ID, "commons-logging", SearchType.SCORED);
126
127 assertEquals(
128 "(a:commons-logging (a:commons-logging*)^0.8) ((+artifactId:commons +artifactId:logging*) artifactId:\"commons logging\")",
129 q.toString());
130
131
132 q = indexer.constructQuery(MAVEN.NAME, "Some artifact name from Pom", SearchType.SCORED);
133
134 assertEquals("(+n:some +n:artifact +n:name +n:from +n:Pom*) n:\"some artifact name from pom\"", q.toString());
135
136
137 q = indexer.constructQuery(MAVEN.NAME, "some artifact name from Pom", SearchType.EXACT);
138
139 assertNull(q);
140 }
141
142 public void performQueryCreatorNGSearch(NexusIndexer indexer, IndexingContext context) throws Exception {
143 String qstr;
144 Query q;
145
146 IteratorSearchRequest req;
147
148 IteratorSearchResponse res;
149
150
151
152
153 qstr = "commons-logg";
154 q = indexer.constructQuery(MAVEN.GROUP_ID, qstr, SearchType.SCORED);
155
156 req = new IteratorSearchRequest(q, context);
157
158 res = indexer.searchIterator(req);
159
160 checkResults(
161 MAVEN.GROUP_ID, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case01.txt"));
162
163
164
165
166 qstr = "commons logg";
167 q = indexer.constructQuery(MAVEN.GROUP_ID, qstr, SearchType.SCORED);
168
169 req = new IteratorSearchRequest(q, context);
170
171 res = indexer.searchIterator(req);
172
173 checkResults(
174 MAVEN.GROUP_ID, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case02.txt"));
175
176
177
178 qstr = "commons";
179 q = indexer.constructQuery(MAVEN.GROUP_ID, qstr, SearchType.SCORED);
180
181 req = new IteratorSearchRequest(q, context);
182
183 res = indexer.searchIterator(req);
184
185 checkResults(
186 MAVEN.GROUP_ID, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case03.txt"));
187
188
189
190 qstr = "log";
191 q = indexer.constructQuery(MAVEN.GROUP_ID, qstr, SearchType.SCORED);
192
193 req = new IteratorSearchRequest(q, context);
194
195 res = indexer.searchIterator(req);
196
197 checkResults(
198 MAVEN.GROUP_ID, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case04.txt"));
199
200
201
202
203 qstr = "1.0";
204 q = indexer.constructQuery(MAVEN.VERSION, "1.0", SearchType.SCORED);
205
206 req = new IteratorSearchRequest(q, context);
207
208 res = indexer.searchIterator(req);
209
210 checkResults(
211 MAVEN.VERSION, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case05.txt"));
212
213
214
215 qstr = "1.0";
216 q = indexer.constructQuery(MAVEN.VERSION, qstr, SearchType.EXACT);
217
218 req = new IteratorSearchRequest(q, context);
219
220 res = indexer.searchIterator(req);
221
222 checkResults(
223 MAVEN.VERSION, qstr, q, res, getTestFile("src/test/resources/testQueryCreatorNGSearch/case06.txt"));
224
225
226
227
228
229 Query g = indexer.constructQuery(MAVEN.GROUP_ID, "commons-logging", SearchType.EXACT);
230 Query a = indexer.constructQuery(MAVEN.ARTIFACT_ID, "commons-logging", SearchType.EXACT);
231 Query v = indexer.constructQuery(MAVEN.VERSION, "1.0.4", SearchType.EXACT);
232 Query p = indexer.constructQuery(MAVEN.PACKAGING, "jar", SearchType.EXACT);
233 Query c = indexer.constructQuery(MAVEN.CLASSIFIER, Field.NOT_PRESENT, SearchType.EXACT);
234
235
236 BooleanQuery bq = new BooleanQuery.Builder()
237 .add(g, Occur.MUST)
238 .add(a, Occur.MUST)
239 .add(v, Occur.MUST)
240 .add(p, Occur.MUST)
241 .add(c, Occur.MUST_NOT)
242 .build();
243
244
245 Collection<ArtifactInfo> ais = indexer.identify(bq, Collections.singletonList(context));
246
247 assertEquals(1, ais.size());
248
249 ArtifactInfo ai = ais.iterator().next();
250
251
252 assertTrue(ai != null);
253
254
255 assertEquals(
256 "commons-logging:commons-logging:1.0.4:null:jar",
257 ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion() + ":" + ai.getClassifier() + ":"
258 + ai.getPackaging());
259 }
260
261 @Test
262 public void testQueryCreatorNGSearch() throws Exception {
263 NexusIndexer indexer = prepare();
264
265 performQueryCreatorNGSearch(indexer, context);
266 }
267
268 @Test
269 public void testQueryCreatorNGSearchOnMergedContext() throws Exception {
270 NexusIndexer indexer = prepare();
271
272 File indexMergedDir = super.getDirectory("index/testMerged");
273
274 IndexingContext mergedContext = new MergedIndexingContext(
275 "test",
276 "merged",
277 context.getRepository(),
278 indexMergedDir,
279 true,
280 new StaticContextMemberProvider(Collections.singletonList(context)));
281
282 performQueryCreatorNGSearch(indexer, mergedContext);
283 }
284
285
286
287
288 public void checkResults(Field field, String query, Query q, IteratorSearchResponse res, File expectedResults)
289 throws IOException {
290
291
292 boolean print = true;
293
294 StringWriter sw = new StringWriter();
295
296 PrintWriter pw = new PrintWriter(sw);
297
298 String line;
299
300 line = "### Searched for field " + field.toString() + " using query \"" + query + "\" (QC create LQL \""
301 + q.toString() + "\")";
302
303 if (print) {
304 System.out.println(line);
305 }
306
307 pw.println(line);
308
309 int totalHits = 0;
310
311 for (ArtifactInfo ai : res) {
312 line = ai.getContext() + " :: " + ai.getGroupId() + ":" + ai.getArtifactId() + ":" + ai.getVersion() + ":"
313 + ai.getClassifier() + ":" + ai.getPackaging();
314
315 if (print) {
316 System.out.println(line);
317 }
318
319 pw.println(line);
320
321 totalHits++;
322 }
323
324 line = "### TOTAL:" + totalHits + " (response said " + res.getTotalHits() + ")";
325
326 if (print) {
327 System.out.println(line);
328 }
329
330 pw.println(line);
331
332
333
334 StringWriter ressw = new StringWriter();
335 PrintWriter respw = new PrintWriter(ressw);
336
337 BufferedReader reader = new BufferedReader(new FileReader(expectedResults, StandardCharsets.UTF_8));
338 String currentline;
339
340 while ((currentline = reader.readLine()) != null) {
341 respw.println(currentline);
342 }
343
344 String shouldBe = ressw.toString();
345 String whatWeHave = sw.toString();
346
347
348 assertEquals("Search results inconsistent!", shouldBe, whatWeHave);
349 }
350
351 @Test
352 public void testSearchIterator() throws Exception {
353 NexusIndexer indexer = prepare();
354
355 Query q = indexer.constructQuery(MAVEN.GROUP_ID, "qdox", SearchType.SCORED);
356
357 IteratorSearchRequest request = new IteratorSearchRequest(q);
358
359 IteratorSearchResponse response = indexer.searchIterator(request);
360
361 assertEquals(2, response.getTotalHits());
362
363 for (ArtifactInfo ai : response.getResults()) {
364 assertEquals("GroupId must match \"qdox\"!", "qdox", ai.getGroupId());
365 }
366 }
367
368 @Test
369 public void testSearchIteratorWithFilter() throws Exception {
370 NexusIndexer indexer = prepare();
371
372 Query q = indexer.constructQuery(MAVEN.GROUP_ID, "qdox", SearchType.SCORED);
373
374 IteratorSearchRequest request = new IteratorSearchRequest(q, (ctx, ai) -> {
375
376 return !StringUtils.equals(ai.getVersion(), "1.5");
377 });
378
379 IteratorSearchResponse response = indexer.searchIterator(request);
380
381 assertEquals(2, response.getTotalHits());
382
383 assertTrue(
384 "Iterator has to have next (2 found, 1 filtered out)",
385 response.getResults().hasNext());
386
387 ArtifactInfo ai = response.getResults().next();
388
389 assertEquals("1.5 is filtered out, so 1.6.1 must appear here!", "1.6.1", ai.getVersion());
390 }
391
392 @Test
393 public void testSearchGrouped() throws Exception {
394 NexusIndexer indexer = prepare();
395
396 {
397 Query q = indexer.constructQuery(MAVEN.GROUP_ID, "qdox", SearchType.SCORED);
398 GroupedSearchRequest request = new GroupedSearchRequest(q, new GAGrouping());
399 GroupedSearchResponse response = indexer.searchGrouped(request);
400 Map<String, ArtifactInfoGroup> r = response.getResults();
401 assertEquals(1, r.size());
402
403 ArtifactInfoGroup gi0 = r.values().iterator().next();
404 assertEquals("qdox : qdox", gi0.getGroupKey());
405 List<ArtifactInfo> list = new ArrayList<>(gi0.getArtifactInfos());
406 ArtifactInfo ai0 = list.get(0);
407 assertEquals("1.6.1", ai0.getVersion());
408 ArtifactInfo ai1 = list.get(1);
409 assertEquals("1.5", ai1.getVersion());
410 assertEquals("test", ai1.getRepository());
411 }
412 {
413 WildcardQuery q = new WildcardQuery(new Term(ArtifactInfo.UINFO, "commons-log*"));
414 GroupedSearchRequest request = new GroupedSearchRequest(q, new GAGrouping(), String.CASE_INSENSITIVE_ORDER);
415 GroupedSearchResponse response = indexer.searchGrouped(request);
416 Map<String, ArtifactInfoGroup> r = response.getResults();
417 assertEquals(1, r.size());
418
419 ArtifactInfoGroup gi1 = r.values().iterator().next();
420 assertEquals("commons-logging : commons-logging", gi1.getGroupKey());
421 }
422 }
423
424 @Test
425 public void testSearchFlat() throws Exception {
426 NexusIndexer indexer = prepare();
427
428 {
429 WildcardQuery q = new WildcardQuery(new Term(ArtifactInfo.UINFO, "*testng*"));
430 FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(q));
431 Set<ArtifactInfo> r = response.getResults();
432 assertEquals(r.toString(), 4, r.size());
433 }
434
435 {
436 BooleanQuery bq = new BooleanQuery.Builder()
437 .add(new WildcardQuery(new Term(ArtifactInfo.GROUP_ID, "testng*")), Occur.SHOULD)
438 .add(new WildcardQuery(new Term(ArtifactInfo.ARTIFACT_ID, "testng*")), Occur.SHOULD)
439 .setMinimumNumberShouldMatch(1)
440 .build();
441
442 FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(bq));
443 Set<ArtifactInfo> r = response.getResults();
444
445 assertEquals(r.toString(), 4, r.size());
446 }
447 }
448
449 @Test
450 public void testSearchPackaging() throws Exception {
451 NexusIndexer indexer = prepare();
452
453 WildcardQuery q = new WildcardQuery(new Term(ArtifactInfo.PACKAGING, "maven-plugin"));
454 FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(q));
455 Set<ArtifactInfo> r = response.getResults();
456 assertEquals(r.toString(), 2, r.size());
457 }
458
459 @Test
460 public void testIdentity() throws Exception {
461 NexusIndexer nexus = prepare();
462
463
464
465 Collection<ArtifactInfo> ais = nexus.identify(MAVEN.SHA1, "4d2db265eddf1576cb9d896abc90c7ba46b48d87");
466
467 assertEquals(1, ais.size());
468
469 ArtifactInfo ai = ais.iterator().next();
470
471 assertNotNull(ai);
472
473 assertEquals("qdox", ai.getGroupId());
474
475 assertEquals("qdox", ai.getArtifactId());
476
477 assertEquals("1.5", ai.getVersion());
478
479 assertEquals("test", ai.getRepository());
480
481
482
483 File artifact = new File(getBasedir(), "src/test/repo/qdox/qdox/1.5/qdox-1.5.jar");
484
485 ais = nexus.identify(artifact);
486
487 assertEquals(1, ais.size());
488
489 ai = ais.iterator().next();
490
491 assertNotNull(ai);
492
493 assertEquals("qdox", ai.getGroupId());
494
495 assertEquals("qdox", ai.getArtifactId());
496
497 assertEquals("1.5", ai.getVersion());
498
499 assertEquals("test", ai.getRepository());
500 }
501
502 @Test
503 public void testUpdateArtifact() throws Exception {
504 NexusIndexer indexer = prepare();
505
506 Query q =
507 new TermQuery(new Term(ArtifactInfo.UINFO, "org.apache.maven.plugins|maven-core-it-plugin|1.0|NA|jar"));
508
509 FlatSearchRequest request = new FlatSearchRequest(q);
510
511 FlatSearchResponse response1 = indexer.searchFlat(request);
512 Collection<ArtifactInfo> res1 = response1.getResults();
513 assertEquals(1, res1.size());
514
515 ArtifactInfo ai = res1.iterator().next();
516
517 assertEquals("Maven Core Integration Test Plugin", ai.getName());
518
519 long oldSize = ai.getSize();
520
521 ai.setName("bla bla bla");
522
523 ai.setSize(ai.getSize() + 100);
524
525 IndexingContext indexingContext = indexer.getIndexingContexts().get("test");
526
527
528
529
530
531
532
533
534 indexer.addArtifactToIndex(new ArtifactContext(null, null, null, ai, null), indexingContext);
535
536 FlatSearchResponse response2 = indexer.searchFlat(request);
537 Collection<ArtifactInfo> res2 = response2.getResults();
538 assertEquals(1, res2.size());
539
540 ArtifactInfo ai2 = res2.iterator().next();
541
542 assertEquals(oldSize + 100, ai2.getSize());
543
544 assertEquals("bla bla bla", ai2.getName());
545 }
546
547 @Test
548 public void testUnpack() throws Exception {
549 NexusIndexer indexer = prepare();
550
551 String indexId = context.getId();
552 String repositoryId = context.getRepositoryId();
553 File repository = context.getRepository();
554 String repositoryUrl = context.getRepositoryUrl();
555 List<IndexCreator> indexCreators = context.getIndexCreators();
556
557
558 final File targetDir = Files.createTempDirectory("testIndexTimestamp").toFile();
559 targetDir.deleteOnExit();
560
561 final IndexPacker indexPacker = lookup(IndexPacker.class);
562 final IndexSearcher indexSearcher = context.acquireIndexSearcher();
563 try {
564 final IndexPackingRequest request =
565 new IndexPackingRequest(context, indexSearcher.getIndexReader(), targetDir);
566 indexPacker.packIndex(request);
567 } finally {
568 context.releaseIndexSearcher(indexSearcher);
569 }
570
571 indexer.removeIndexingContext(context, false);
572
573 Directory newDirectory = new ByteBuffersDirectory();
574
575 IndexingContext newContext = indexer.addIndexingContext(
576 indexId,
577 repositoryId,
578 repository,
579 newDirectory,
580 repositoryUrl,
581 null,
582 indexCreators);
583
584 final IndexUpdater indexUpdater = lookup(IndexUpdater.class);
585 indexUpdater.fetchAndUpdateIndex(
586 new IndexUpdateRequest(newContext, new DefaultIndexUpdater.FileFetcher(targetDir)));
587
588 WildcardQuery q = new WildcardQuery(new Term(ArtifactInfo.PACKAGING, "maven-plugin"));
589 FlatSearchResponse response = indexer.searchFlat(new FlatSearchRequest(q));
590 Collection<ArtifactInfo> infos = response.getResults();
591
592 assertEquals(infos.toString(), 2, infos.size());
593 }
594
595 private NexusIndexer prepare() throws Exception, IOException, UnsupportedExistingLuceneIndexException {
596 NexusIndexer indexer = lookup(NexusIndexer.class);
597
598
599 File indexDir = super.getDirectory("index/test");
600 super.deleteDirectory(indexDir);
601
602 File repo = new File(getBasedir(), "src/test/repo");
603
604 context = indexer.addIndexingContext("test", "test", repo, indexDir, null, null, DEFAULT_CREATORS);
605 indexer.scan(context);
606
607
608
609
610
611
612
613
614
615 return indexer;
616 }
617
618
619
620
621
622
623
624
625
626
627
628 }