View Javadoc
1   package de.dlr.shepard.common.search.services;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertThrows;
5   import static org.junit.jupiter.api.Assertions.assertTrue;
6   
7   import de.dlr.shepard.auth.security.AuthenticationContext;
8   import de.dlr.shepard.auth.security.JWTPrincipal;
9   import de.dlr.shepard.auth.users.entities.User;
10  import de.dlr.shepard.auth.users.services.UserService;
11  import de.dlr.shepard.common.exceptions.ShepardParserException;
12  import de.dlr.shepard.common.search.io.ResponseBody;
13  import de.dlr.shepard.common.search.io.SearchBody;
14  import de.dlr.shepard.common.search.io.SearchParams;
15  import de.dlr.shepard.common.search.io.SearchScope;
16  import de.dlr.shepard.common.util.TraversalRules;
17  import de.dlr.shepard.context.collection.entities.Collection;
18  import de.dlr.shepard.context.collection.entities.DataObject;
19  import de.dlr.shepard.context.collection.io.CollectionIO;
20  import de.dlr.shepard.context.collection.io.DataObjectIO;
21  import de.dlr.shepard.context.collection.services.CollectionService;
22  import de.dlr.shepard.context.collection.services.DataObjectService;
23  import de.dlr.shepard.context.references.timeseriesreference.io.TimeseriesReferenceIO;
24  import de.dlr.shepard.context.references.timeseriesreference.model.TimeseriesReference;
25  import de.dlr.shepard.context.references.timeseriesreference.services.TimeseriesReferenceService;
26  import de.dlr.shepard.context.semantic.SemanticRepositoryType;
27  import de.dlr.shepard.context.semantic.entities.SemanticAnnotation;
28  import de.dlr.shepard.context.semantic.entities.SemanticRepository;
29  import de.dlr.shepard.context.semantic.io.SemanticAnnotationIO;
30  import de.dlr.shepard.context.semantic.io.SemanticRepositoryIO;
31  import de.dlr.shepard.context.semantic.services.SemanticAnnotationService;
32  import de.dlr.shepard.context.semantic.services.SemanticRepositoryService;
33  import de.dlr.shepard.data.timeseries.io.TimeseriesContainerIO;
34  import de.dlr.shepard.data.timeseries.model.Timeseries;
35  import de.dlr.shepard.data.timeseries.model.TimeseriesContainer;
36  import de.dlr.shepard.data.timeseries.model.TimeseriesDataPoint;
37  import de.dlr.shepard.data.timeseries.model.TimeseriesTuple;
38  import de.dlr.shepard.data.timeseries.services.TimeseriesContainerService;
39  import de.dlr.shepard.data.timeseries.services.TimeseriesService;
40  import de.dlr.shepard.integrationtests.WireMockResource;
41  import io.quarkus.test.common.WithTestResource;
42  import io.quarkus.test.junit.QuarkusTest;
43  import jakarta.inject.Inject;
44  import jakarta.transaction.Transactional;
45  import java.util.ArrayList;
46  import java.util.List;
47  import org.junit.jupiter.api.BeforeEach;
48  import org.junit.jupiter.api.Test;
49  
50  @QuarkusTest
51  @WithTestResource(WireMockResource.class)
52  public class ReferenceSearchServiceQuarkusTest {
53  
54    @Inject
55    CollectionService collectionService;
56  
57    @Inject
58    DataObjectService dataObjectService;
59  
60    @Inject
61    ReferenceSearchService referenceSearcher;
62  
63    @Inject
64    TimeseriesReferenceService timeseriesReferenceService;
65  
66    @Inject
67    TimeseriesService timeseriesService;
68  
69    @Inject
70    SemanticRepositoryService semanticRepositoryService;
71  
72    @Inject
73    TimeseriesContainerService timeseriesContainerService;
74  
75    @Inject
76    AuthenticationContext authenticationContext;
77  
78    @Inject
79    UserService userService;
80  
81    @Inject
82    SemanticAnnotationService semanticAnnotationService;
83  
84    private static Collection collection1;
85    private static DataObject dataObjectc1d1;
86    private static DataObject dataObjectc1d2;
87    private static TimeseriesReference annoReference;
88    private static TimeseriesReference noAnnoReference;
89    private static TimeseriesReference conReference;
90    private static TimeseriesContainer tsCon;
91    private static TimeseriesContainer tsCon1;
92    private static Timeseries timeseries1;
93    private static Timeseries timeseries2;
94    private static Timeseries timeseriesCon;
95    private static Timeseries timeseriesCon1;
96    private static SemanticRepository repository;
97    private static User user;
98    private static SemanticAnnotationIO refAnnoToCreate;
99    private static SemanticAnnotationIO tsAnnoToCreate;
100   private static SemanticAnnotationIO tsCon1AnnoToCreate;
101   private static SemanticAnnotation refAnno;
102   private static SemanticAnnotation tsAnno;
103   private static SemanticAnnotation timeseriesCon1Anno;
104   private static String username = "username";
105 
106   @BeforeEach
107   public void setUp() {
108     //create user
109     if (user == null) {
110       User user = new User(username);
111       userService.createOrUpdateUser(user);
112       authenticationContext.setPrincipal(new JWTPrincipal(username, "key"));
113     }
114     //create collection
115     if (collection1 == null) {
116       CollectionIO collection1IO = new CollectionIO();
117       collection1IO.setName("collection1" + System.currentTimeMillis());
118       collection1 = collectionService.createCollection(collection1IO);
119     }
120     //create dataobject1
121     if (dataObjectc1d1 == null) {
122       DataObjectIO dataObjectc1d1IO = new DataObjectIO();
123       dataObjectc1d1IO.setName("c1do1" + System.currentTimeMillis());
124       dataObjectc1d1 = dataObjectService.createDataObject(collection1.getShepardId(), dataObjectc1d1IO);
125     }
126     //create dataobject2
127     if (dataObjectc1d2 == null) {
128       DataObjectIO dataObjectc1d2IO = new DataObjectIO();
129       dataObjectc1d2IO.setName("c1do2" + System.currentTimeMillis());
130       dataObjectc1d2 = dataObjectService.createDataObject(collection1.getShepardId(), dataObjectc1d2IO);
131     }
132     //create timeseriesContainer with content
133     if (tsCon == null) {
134       //create container
135       TimeseriesContainerIO tsConIO = new TimeseriesContainerIO();
136       tsConIO.setName("container");
137       tsCon = timeseriesContainerService.createContainer(tsConIO);
138       //create three timeseries
139       TimeseriesDataPoint dataPoint = new TimeseriesDataPoint(4l, true);
140       List<TimeseriesDataPoint> points = new ArrayList<TimeseriesDataPoint>();
141       points.add(dataPoint);
142       TimeseriesTuple ts1 = new TimeseriesTuple("m1", "d1", "l1", "s1", "f1");
143       TimeseriesTuple ts2 = new TimeseriesTuple("m2", "d2", "l2", "s2", "f2");
144       TimeseriesTuple ttCon = new TimeseriesTuple("md", "dd", "ld", "ds", "fd");
145       timeseries1 = timeseriesService.saveDataPoints(tsCon.getId(), ts1, points);
146       timeseries2 = timeseriesService.saveDataPoints(tsCon.getId(), ts2, points);
147       timeseriesCon = timeseriesService.saveDataPoints(tsCon.getId(), ttCon, points);
148       //create repository
149       SemanticRepositoryIO repToCreate = new SemanticRepositoryIO();
150       repToCreate.setName("SemanticRepository");
151       repToCreate.setType(SemanticRepositoryType.SPARQL);
152       repToCreate.setEndpoint(WireMockResource.getWireMockServerURlWithPath("/sparql"));
153       repository = semanticRepositoryService.createRepository(repToCreate);
154       //create annotated reference
155       TimeseriesReferenceIO ref1IO = new TimeseriesReferenceIO();
156       ref1IO.setName("refAnno");
157       ref1IO.setStart(5l);
158       ref1IO.setEnd(16l);
159       List<TimeseriesTuple> timeseries1 = new ArrayList<TimeseriesTuple>();
160       timeseries1.add(ts1);
161       ref1IO.setTimeseries(timeseries1);
162       ref1IO.setTimeseriesContainerId(tsCon.getId());
163       annoReference = timeseriesReferenceService.createReference(
164         collection1.getShepardId(),
165         dataObjectc1d1.getShepardId(),
166         ref1IO
167       );
168       //create reference without annotations
169       TimeseriesReferenceIO ref2IO = new TimeseriesReferenceIO();
170       ref2IO.setName("refWithoutAnno");
171       ref2IO.setStart(0l);
172       ref2IO.setEnd(9l);
173       List<TimeseriesTuple> timeseries2 = new ArrayList<TimeseriesTuple>();
174       timeseries2.add(ts2);
175       ref2IO.setTimeseries(timeseries2);
176       ref2IO.setTimeseriesContainerId(tsCon.getId());
177       noAnnoReference = timeseriesReferenceService.createReference(
178         collection1.getShepardId(),
179         dataObjectc1d1.getShepardId(),
180         ref2IO
181       );
182       //create third timeseriesReference
183       TimeseriesReferenceIO conRefIO = new TimeseriesReferenceIO();
184       conRefIO.setName("conRef");
185       conRefIO.setStart(0l);
186       conRefIO.setEnd(9l);
187       List<TimeseriesTuple> timeseriesCon = new ArrayList<TimeseriesTuple>();
188       timeseriesCon.add(ttCon);
189       conRefIO.setTimeseries(timeseriesCon);
190       conRefIO.setTimeseriesContainerId(tsCon.getId());
191       conReference = timeseriesReferenceService.createReference(
192         collection1.getShepardId(),
193         dataObjectc1d2.getShepardId(),
194         conRefIO
195       );
196     }
197     //create another timeseriesContainer with timeseries sharing quintuple
198     if (tsCon1 == null) {
199       //create container
200       TimeseriesContainerIO tsCon1IO = new TimeseriesContainerIO();
201       tsCon1IO.setName("container1");
202       tsCon1 = timeseriesContainerService.createContainer(tsCon1IO);
203       //create two timeseries
204       TimeseriesDataPoint dataPoint = new TimeseriesDataPoint(4l, true);
205       List<TimeseriesDataPoint> points = new ArrayList<TimeseriesDataPoint>();
206       points.add(dataPoint);
207       TimeseriesTuple ttCon1 = new TimeseriesTuple("md", "dd", "ld", "ds", "fd");
208       timeseriesCon1 = timeseriesService.saveDataPoints(tsCon1.getId(), ttCon1, points);
209     }
210     // annotate Reference
211     if (refAnnoToCreate == null) {
212       refAnnoToCreate = new SemanticAnnotationIO();
213       refAnnoToCreate.setPropertyIRI("http://dbpedia.org/ontology/ingredient");
214       refAnnoToCreate.setPropertyRepositoryId(repository.getId());
215       refAnnoToCreate.setValueIRI("http://dbpedia.org/resource/Almond_milk");
216       refAnnoToCreate.setValueRepositoryId(repository.getId());
217       refAnno = semanticAnnotationService.createAnnotationByShepardId(annoReference.getId(), refAnnoToCreate);
218     }
219     // annotate Timeseries
220     if (tsAnnoToCreate == null) {
221       tsAnnoToCreate = new SemanticAnnotationIO();
222       tsAnnoToCreate.setPropertyIRI("http://dbpedia.org/ontology/ingredient");
223       tsAnnoToCreate.setPropertyRepositoryId(repository.getId());
224       tsAnnoToCreate.setValueIRI("http://dbpedia.org/resource/milk");
225       tsAnnoToCreate.setValueRepositoryId(repository.getId());
226       tsAnno = semanticAnnotationService.createAnnotationByNeo4jId(timeseries2.getId(), tsAnnoToCreate);
227     }
228     if (tsCon1AnnoToCreate == null) {
229       tsCon1AnnoToCreate = new SemanticAnnotationIO();
230       tsCon1AnnoToCreate.setPropertyIRI("http://dbpedia.org/ontology/ingredient");
231       tsCon1AnnoToCreate.setPropertyRepositoryId(repository.getId());
232       tsCon1AnnoToCreate.setValueIRI("http://dbpedia.org/resource/milk");
233       tsCon1AnnoToCreate.setValueRepositoryId(repository.getId());
234       timeseriesCon1Anno = semanticAnnotationService.createAnnotationByNeo4jId(
235         timeseriesCon1.getId(),
236         tsCon1AnnoToCreate
237       );
238     }
239   }
240 
241   @Test
242   @Transactional
243   public void findExactlyOneReferenceByIRIEquality() {
244     String query =
245       "{\"property\": \"hasAnnotationIRI\", \"value\": \"http://dbpedia.org/ontology/ingredient::http://dbpedia.org/resource/Almond_milk\", \"operator\": \"eq\"}";
246     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
247     ResponseBody response = referenceSearcher.search(body);
248     assertEquals(1, response.getResults().length);
249     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
250   }
251 
252   @Test
253   @Transactional
254   public void findNoReference() {
255     String query = "{\"property\": \"hasAnnotation\", \"value\": \"ingre.*::Almon.*\", \"operator\": \"eq\"}";
256     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
257     ResponseBody response = referenceSearcher.search(body);
258     assertEquals(0, response.getResults().length);
259   }
260 
261   @Test
262   @Transactional
263   public void findByPropertyIRIContains() {
264     String query = "{\"property\": \"propertyIRI\", \"value\": \"dbpedia\", \"operator\": \"contains\"}";
265     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
266     ResponseBody response = referenceSearcher.search(body);
267     assertEquals(true, response.getResults().length > 0);
268     //assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
269   }
270 
271   @Test
272   @Transactional
273   public void findByAnnotationPropertyIRIEq() {
274     String query =
275       "{\"property\": \"referencedTimeseriesPropertyIRI\", \"value\": \"" +
276       tsAnno.getPropertyIRI() +
277       "\", \"operator\": \"eq\"}";
278     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
279     ResponseBody response = referenceSearcher.search(body);
280     assertEquals(1, response.getResults().length);
281     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
282   }
283 
284   @Test
285   @Transactional
286   public void findByAnnotationValueIRIEq() {
287     String query =
288       "{\"property\": \"referencedTimeseriesValueIRI\", \"value\": \"" +
289       tsAnno.getValueIRI() +
290       "\", \"operator\": \"eq\"}";
291     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
292     ResponseBody response = referenceSearcher.search(body);
293     assertEquals(1, response.getResults().length);
294     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
295   }
296 
297   @Test
298   @Transactional
299   public void findByAnnotationValueIRIContains() {
300     String query = "{\"property\": \"referencedTimeseriesValueIRI\", \"value\": \"ht\", \"operator\": \"contains\"}";
301     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
302     ResponseBody response = referenceSearcher.search(body);
303     assertEquals(1, response.getResults().length);
304     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
305   }
306 
307   @Test
308   @Transactional
309   public void findByTimeseriesAnnotationEq() {
310     String query =
311       "{\"property\": \"referencedTimeseriesHasAnnotation\", \"value\": \"" +
312       tsAnno.getPropertyName() +
313       "::" +
314       tsAnno.getValueName() +
315       "\", \"operator\": \"eq\"}";
316     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
317     ResponseBody response = referenceSearcher.search(body);
318     assertEquals(1, response.getResults().length);
319     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
320   }
321 
322   @Test
323   @Transactional
324   public void findByTimeseriesAnnotationIRIEq() {
325     String query =
326       "{\"property\": \"referencedTimeseriesHasAnnotationIRI\", \"value\": \"" +
327       tsAnno.getPropertyIRI() +
328       "::" +
329       tsAnno.getValueIRI() +
330       "\", \"operator\": \"eq\"}";
331     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
332     ResponseBody response = referenceSearcher.search(body);
333     assertEquals(1, response.getResults().length);
334     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
335   }
336 
337   @Test
338   @Transactional
339   public void dontFindByTimeseriesAnnotationIRIEq() {
340     String query =
341       "{\"property\": \"referencedTimeseriesHasAnnotationIRI\", \"value\": \"" +
342       tsAnno.getPropertyIRI() +
343       "::" +
344       tsAnno.getValueName() +
345       "\", \"operator\": \"eq\"}";
346     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
347     ResponseBody response = referenceSearcher.search(body);
348     assertEquals(0, response.getResults().length);
349   }
350 
351   @Test
352   @Transactional
353   public void findByValueIRIContains() {
354     String query = "{\"property\": \"valueIRI\", \"value\": \"Almond\", \"operator\": \"contains\"}";
355     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
356     ResponseBody response = referenceSearcher.search(body);
357     assertEquals(true, response.getResults().length > 0);
358     //assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
359   }
360 
361   @Test
362   @Transactional
363   public void findExactlyOneReferenceByStart() {
364     String query = "{\"property\": \"start\", \"value\": " + annoReference.getStart() + ", \"operator\": \"lt\"}";
365     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
366     ResponseBody response = referenceSearcher.search(body);
367     assertEquals(1, response.getResults().length);
368     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
369   }
370 
371   @Test
372   @Transactional
373   public void findExactlyTwoReferencesByStart() {
374     String query = "{\"property\": \"start\", \"value\": " + noAnnoReference.getStart() + ", \"operator\": \"ge\"}";
375     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
376     ResponseBody response = referenceSearcher.search(body);
377     assertEquals(2, response.getResults().length);
378     assertTrue(
379       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
380       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
381     );
382     assertTrue(
383       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
384       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
385     );
386   }
387 
388   @Test
389   @Transactional
390   public void findExactlyOneReferenceByEnd() {
391     String query = "{\"property\": \"end\", \"value\": " + annoReference.getEnd() + ", \"operator\": \"lt\"}";
392     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
393     ResponseBody response = referenceSearcher.search(body);
394     assertEquals(1, response.getResults().length);
395     assertEquals(noAnnoReference.getId(), response.getResultSet()[0].getReferenceId());
396   }
397 
398   @Test
399   @Transactional
400   public void findExactlyTwoReferencesByEnd() {
401     String query = "{\"property\": \"end\", \"value\": " + noAnnoReference.getStart() + ", \"operator\": \"ge\"}";
402     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
403     ResponseBody response = referenceSearcher.search(body);
404     assertEquals(2, response.getResults().length);
405     assertTrue(
406       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
407       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
408     );
409     assertTrue(
410       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
411       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
412     );
413   }
414 
415   @Test
416   @Transactional
417   public void findExactlyOneReferenceByAnnotationRegMatch() {
418     String query = "{\"property\": \"hasAnnotation\", \"value\": \"ingre.*::Almon.*\", \"operator\": \"regmatch\"}";
419     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
420     ResponseBody response = referenceSearcher.search(body);
421     assertEquals(1, response.getResults().length);
422     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
423   }
424 
425   @Test
426   @Transactional
427   public void findExactlyOneReferenceByReferencedTimeseriesId() {
428     String query =
429       "{\"property\": \"referencedTimeseriesId\", \"value\": " +
430       timeseries1.getTimeseriesId() +
431       ", \"operator\": \"eq\"}";
432     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
433     ResponseBody response = referenceSearcher.search(body);
434     assertEquals(1, response.getResults().length);
435     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
436   }
437 
438   @Test
439   @Transactional
440   public void findExactlyTwoReferencesByReferencedTimeseriesId() {
441     String query = "{\"property\": \"referencedTimeseriesId\", \"value\": 0, \"operator\": \"ge\"}";
442     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
443     ResponseBody response = referenceSearcher.search(body);
444     assertEquals(2, response.getResults().length);
445     assertTrue(
446       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
447       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
448     );
449     assertTrue(
450       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
451       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
452     );
453   }
454 
455   @Test
456   @Transactional
457   public void findExactlyOneReferenceByReferencedMeasurement() {
458     String query = "{\"property\": \"referencedTimeseriesMeasurement\", \"value\": \"m1\", \"operator\": \"eq\"}";
459     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
460     ResponseBody response = referenceSearcher.search(body);
461     assertEquals(1, response.getResults().length);
462     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
463   }
464 
465   @Test
466   @Transactional
467   public void findExactlyTwoReferencesByReferencedMeasurement() {
468     String query = "{\"property\": \"referencedTimeseriesMeasurement\", \"value\": \"m\", \"operator\": \"contains\"}";
469     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
470     ResponseBody response = referenceSearcher.search(body);
471     assertEquals(2, response.getResults().length);
472     assertTrue(
473       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
474       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
475     );
476     assertTrue(
477       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
478       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
479     );
480   }
481 
482   @Test
483   @Transactional
484   public void findExactlyOneReferenceByReferencedDevice() {
485     String query = "{\"property\": \"referencedTimeseriesDevice\", \"value\": \"d1\", \"operator\": \"eq\"}";
486     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
487     ResponseBody response = referenceSearcher.search(body);
488     assertEquals(1, response.getResults().length);
489     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
490   }
491 
492   @Test
493   @Transactional
494   public void findExactlyTwoReferencesByReferencedDevice() {
495     String query = "{\"property\": \"referencedTimeseriesDevice\", \"value\": \"d\", \"operator\": \"contains\"}";
496     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
497     ResponseBody response = referenceSearcher.search(body);
498     assertEquals(2, response.getResults().length);
499     assertTrue(
500       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
501       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
502     );
503     assertTrue(
504       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
505       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
506     );
507   }
508 
509   @Test
510   @Transactional
511   public void findExactlyOneReferenceByReferencedLocation() {
512     String query = "{\"property\": \"referencedTimeseriesLocation\", \"value\": \"l1\", \"operator\": \"eq\"}";
513     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
514     ResponseBody response = referenceSearcher.search(body);
515     assertEquals(1, response.getResults().length);
516     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
517   }
518 
519   @Test
520   @Transactional
521   public void findExactlyTwoReferencesByReferencedLocation() {
522     String query = "{\"property\": \"referencedTimeseriesLocation\", \"value\": \"l\", \"operator\": \"contains\"}";
523     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
524     ResponseBody response = referenceSearcher.search(body);
525     assertEquals(2, response.getResults().length);
526     assertTrue(
527       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
528       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
529     );
530     assertTrue(
531       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
532       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
533     );
534   }
535 
536   @Test
537   @Transactional
538   public void findExactlyOneReferenceByReferencedField() {
539     String query = "{\"property\": \"referencedTimeseriesField\", \"value\": \"f1\", \"operator\": \"eq\"}";
540     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
541     ResponseBody response = referenceSearcher.search(body);
542     assertEquals(1, response.getResults().length);
543     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
544   }
545 
546   @Test
547   @Transactional
548   public void findExactlyTwoReferencesByReferencedField() {
549     String query = "{\"property\": \"referencedTimeseriesField\", \"value\": \"f\", \"operator\": \"contains\"}";
550     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
551     ResponseBody response = referenceSearcher.search(body);
552     assertEquals(2, response.getResults().length);
553     assertTrue(
554       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
555       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
556     );
557     assertTrue(
558       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
559       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
560     );
561   }
562 
563   @Test
564   @Transactional
565   public void findExactlyOneReferenceByReferencedSymbolicName() {
566     String query = "{\"property\": \"referencedTimeseriesSymbolicName\", \"value\": \"s1\", \"operator\": \"eq\"}";
567     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
568     ResponseBody response = referenceSearcher.search(body);
569     assertEquals(1, response.getResults().length);
570     assertEquals(annoReference.getId(), response.getResultSet()[0].getReferenceId());
571   }
572 
573   @Test
574   @Transactional
575   public void findExactlyTwoReferencesByReferencedSymbolicName() {
576     String query = "{\"property\": \"referencedTimeseriesSymbolicName\", \"value\": \"s\", \"operator\": \"contains\"}";
577     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
578     ResponseBody response = referenceSearcher.search(body);
579     assertEquals(2, response.getResults().length);
580     assertTrue(
581       response.getResultSet()[0].getReferenceId().equals(annoReference.getId()) ||
582       response.getResultSet()[1].getReferenceId().equals(annoReference.getId())
583     );
584     assertTrue(
585       response.getResultSet()[0].getReferenceId().equals(noAnnoReference.getId()) ||
586       response.getResultSet()[1].getReferenceId().equals(noAnnoReference.getId())
587     );
588   }
589 
590   @Test
591   @Transactional
592   public void dontFindViaTimeseriesWithSharedQuintuple() {
593     String query = "{\"property\": \"referencedTimeseriesPropertyIRI\", \"value\": \"h\", \"operator\": \"contains\"}";
594     SearchBody body = buildBody(collection1, dataObjectc1d2, query);
595     ResponseBody response = referenceSearcher.search(body);
596     assertEquals(0, response.getResults().length);
597   }
598 
599   @Test
600   @Transactional
601   public void provokeExceptionByInvalidAnnotationIRI() {
602     String wrongAnnotation = "http://dbpedia.org/ontology/ingredienthttp://dbpedia.org/resource/Almond_milk";
603     String query = "{\"property\": \"hasAnnotationIRI\", \"value\": \"" + wrongAnnotation + "\", \"operator\": \"eq\"}";
604     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
605     assertThrows(ShepardParserException.class, () -> referenceSearcher.search(body));
606   }
607 
608   @Test
609   @Transactional
610   public void provokeExceptionByTooManyDoubleColons() {
611     String wrongAnnotation = "::B::";
612     String query = "{\"property\": \"hasAnnotationIRI\", \"value\": \"" + wrongAnnotation + "\", \"operator\": \"eq\"}";
613     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
614     assertThrows(ShepardParserException.class, () -> referenceSearcher.search(body));
615   }
616 
617   @Test
618   @Transactional
619   public void provokeExceptionByThreeConsecutiveColons() {
620     String wrongAnnotation = ":::";
621     String query = "{\"property\": \"hasAnnotationIRI\", \"value\": \"" + wrongAnnotation + "\", \"operator\": \"eq\"}";
622     SearchBody body = buildBody(collection1, dataObjectc1d1, query);
623     assertThrows(ShepardParserException.class, () -> referenceSearcher.search(body));
624   }
625 
626   private SearchBody buildBody(Collection collection, DataObject dataObject, String query) {
627     SearchScope scope = new SearchScope();
628     scope.setCollectionId(collection.getId());
629     scope.setDataObjectId(dataObject.getId());
630     TraversalRules[] rules = {};
631     scope.setTraversalRules(rules);
632     SearchScope[] scopes = { scope };
633     SearchParams params = new SearchParams();
634     params.setQuery(query);
635     SearchBody body = new SearchBody();
636     body.setSearchParams(params);
637     body.setScopes(scopes);
638     return body;
639   }
640 }