package org.jboss.test.capedwarf.cluster.test;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.appengine.api.search.Document;
import com.google.appengine.api.search.Field;
import com.google.appengine.api.search.GetIndexesRequest;
import com.google.appengine.api.search.GetRequest;
import com.google.appengine.api.search.GetResponse;
import com.google.appengine.api.search.Index;
import com.google.appengine.api.search.IndexSpec;
import com.google.appengine.api.search.Results;
import com.google.appengine.api.search.ScoredDocument;
import com.google.appengine.api.search.SearchService;
import com.google.appengine.api.search.SearchServiceFactory;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
import org.jboss.test.capedwarf.common.support.JBoss;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
/**
* @author Matej Lazar
*/
@RunWith(Arquillian.class)
@Category(JBoss.class)
public class SearchTest extends ClusteredTestBase {
private SearchService service;
@Before
public void setUp() throws Exception {
service = SearchServiceFactory.getSearchService();
}
@InSequence(1)
@Test
@OperateOnDeployment("dep1")
public void cleanpOnStart() {
clear();
Index index = getTestIndex();
List<Document> documents = getAllDocumentsIn(index );
assertEquals(0, documents.size());
}
@InSequence(2)
@Test
@OperateOnDeployment("dep1")
public void testTwoDocumentsHaveDistinctGeneratedIdsOnDep1() {
Document doc1 = newEmptyDocument(); // id-less document
Document doc2 = newEmptyDocument(); // id-less document
Index index = getTestIndex();
index.put(doc1, doc2);
waitForSync();
List<Document> documents = getAllDocumentsIn(index);
assertEquals(2, documents.size());
assertFalse(documents.get(0).getId().equals(documents.get(1).getId()));
}
@InSequence(3)
@Test
@OperateOnDeployment("dep2")
public void testTwoDocumentsHaveDistinctGeneratedIdsOnDep2() {
Index index = getTestIndex();
Document doc = newEmptyDocument(); // id-less document
index.put(doc);
waitForSync();
List<Document> documents = getAllDocumentsIn(index);
assertEquals(3, documents.size());
assertFalse(documents.get(0).getId().equals(documents.get(1).getId()));
assertFalse(documents.get(0).getId().equals(documents.get(2).getId()));
assertFalse(documents.get(1).getId().equals(documents.get(2).getId()));
}
@InSequence(4)
@Test
@OperateOnDeployment("dep1")
public void testAddOverwritesPreviousDocumentWithSameIdOnDep1() {
clear();
String documentId = "foo";
Index index = getTestIndex();
Document doc1 = Document.newBuilder()
.setId(documentId)
.setRank(123)
.addField(newField("bar").setText("ding"))
.build();
index.put(doc1);
Document doc2 = Document.newBuilder()
.setId(documentId)
.setRank(456)
.addField(newField("bar").setText("dong"))
.build();
index.put(doc2);
waitForSync();
List<Document> results = getAllDocumentsIn(index);
assertEquals(1, results.size());
Document retrievedDoc = results.get(0);
assertEquals(doc2, retrievedDoc);
assertEquals(456, retrievedDoc.getRank());
assertEquals("dong", retrievedDoc.getOnlyField("bar").getText());
}
@InSequence(5)
@Test
@OperateOnDeployment("dep2")
public void testAddOverwritesPreviousDocumentWithSameIdOnDep2() {
waitForSync();
String documentId = "foo";
Index index = getTestIndex();
List<Document> results = getAllDocumentsIn(index);
Assert.assertEquals(1, results.size());
Document retrievedDoc = results.get(0);
assertEquals(456, retrievedDoc.getRank());
assertEquals("dong", retrievedDoc.getOnlyField("bar").getText());
Document doc1 = Document.newBuilder()
.setId(documentId)
.setRank(789)
.addField(newField("bar").setText("dooong"))
.build();
index.put(doc1);
waitForSync();
results = getAllDocumentsIn(index);
assertEquals(1, results.size());
retrievedDoc = results.get(0);
assertEquals(doc1, retrievedDoc);
assertEquals(789, retrievedDoc.getRank());
assertEquals("dooong", retrievedDoc.getOnlyField("bar").getText());
}
@InSequence(10)
@Test
@OperateOnDeployment("dep1")
public void testSearchBySingleFieldOnDep1() throws Exception {
Index index = getTestIndex();
index.put(newDocument("fooaaa", newField("foo").setText("aaa")));
index.put(newDocument("foobbb", newField("foo").setText("bbb")));
waitForSync();
assertSearchYields(index, "foo:aaa", "fooaaa");
}
@InSequence(20)
@Test
@OperateOnDeployment("dep2")
public void testSearchBySingleFieldOnDep2() throws Exception {
Index index = getTestIndex();
index.put(newDocument("fooccc", newField("foo").setText("ccc")));
waitForSync();
assertSearchYields(index, "foo:bbb", "foobbb");
assertSearchYields(index, "foo:ccc", "fooccc");
clear();
}
@InSequence(30)
@Test
@OperateOnDeployment("dep1")
public void testSearchDisjunctionOnDep1() {
Index index = getTestIndex();
index.put(newDocument("fooaaa", newField("foo").setText("aaa"), newField("bar").setText("bbb")));
index.put(newDocument("foobbb", newField("foo").setText("bbb"), newField("bar").setText("ccc")));
index.put(newDocument("fooccc", newField("foo").setText("ccc"), newField("bar").setText("bbb")));
waitForSync();
assertSearchYields(index, "foo:aaa OR bar:bbb", "fooaaa", "fooccc");
}
@InSequence(40)
@Test
@OperateOnDeployment("dep2")
public void testSearchDisjunctionOnDep2() {
Index index = getTestIndex();
assertSearchYields(index, "foo:aaa OR bar:bbb", "fooaaa", "fooccc");
index.put(newDocument("fooddd", newField("foo").setText("ddd"), newField("bar").setText("bbb")));
waitForSync();
assertSearchYields(index, "foo:aaa OR bar:bbb", "fooaaa", "fooccc", "fooddd");
}
@InSequence(50)
@Test
@OperateOnDeployment("dep1")
public void testSearchReturnsDocumentsInCorrectIndexOnDep1() {
Index fooIndex = getIndex("fooIndex");
fooIndex.put(newDocument("foo", newField("foo").setText("aaa")));
Index barIndex = getIndex("barIndex");
barIndex.put(newDocument("bar", newField("foo").setText("aaa")));
waitForSync();
assertSearchYields(fooIndex, "foo:aaa", "foo");
}
@InSequence(60)
@Test
@OperateOnDeployment("dep2")
public void testSearchReturnsDocumentsInCorrectIndexOnDep2() {
Index fooIndex = getIndex("fooIndex");
assertSearchYields(fooIndex, "foo:aaa", "foo");
Index barIndex = getIndex("barIndex");
assertSearchYields(barIndex, "foo:aaa", "bar");
fooIndex.put(newDocument("foobbb", newField("foo").setText("aaa")));
waitForSync();
assertSearchYields(fooIndex, "foo:aaa", "foo", "foobbb");
}
@InSequence(70)
@Test
@OperateOnDeployment("dep1")
public void testSearchOnAllFieldsOnDep1() {
clear();
Index index = getTestIndex();
index.put(newDocument(newField("foo").setText("aaa"), newField("bar").setText("bbb")));
index.put(newDocument(newField("foo").setText("bbb"), newField("bar").setText("aaa")));
index.put(newDocument(newField("foo").setText("bbb"), newField("bar").setText("bbb")));
waitForSync();
assertEquals(2, index.search("aaa").getResults().size());
}
@InSequence(80)
@Test
@OperateOnDeployment("dep2")
public void testSearchOnAllFieldsOnDep2() {
Index index = getTestIndex();
assertEquals(2, index.search("aaa").getResults().size());
index.put(newDocument(newField("foo").setText("aaa"), newField("bar").setText("aaa")));
index.put(newDocument(newField("foo").setText("aaa"), newField("bar").setText("ccc")));
index.put(newDocument(newField("foo").setText("ccc"), newField("bar").setText("ccc")));
waitForSync();
assertEquals(4, index.search("aaa").getResults().size());
}
@InSequence(90)
@Test
@OperateOnDeployment("dep1")
public void testComplexSearch1OnDep1() {
Index index = getTestIndex();
index.put(newDocument("bm", newField("author").setText("Bob Marley")));
index.put(newDocument("rj", newField("author").setText("Rose Jones")));
index.put(newDocument("rt", newField("author").setText("Rose Trunk")));
index.put(newDocument("tj", newField("author").setText("Tom Jones")));
waitForSync();
assertSearchYields(index, "author:(bob OR ((rose OR tom) AND jones))", "bm", "rj", "tj");
}
@InSequence(100)
@Test
@OperateOnDeployment("dep2")
public void testComplexSearch1OnDep2() {
Index index = getTestIndex();
assertSearchYields(index, "author:(bob OR ((rose OR tom) AND jones))", "bm", "rj", "tj");
index.put(newDocument("zm", newField("author").setText("Ziggy Marley")));
index.put(newDocument("bd", newField("author").setText("Bob Dylan")));
waitForSync();
assertSearchYields(index, "author:(bob OR ((rose OR tom) AND jones))", "bm", "rj", "tj", "bd");
}
@InSequence(1000)
@Test
@OperateOnDeployment("dep1")
public void tearDownOnDep1() throws Exception {
clear();
}
@InSequence(1000)
@Test
@OperateOnDeployment("dep2")
public void tearDownOnDep2() throws Exception {
clear();
}
private void assertSearchYields(Index index, String queryString, String... documentIds) {
Results<ScoredDocument> results = index.search(queryString);
Collection<ScoredDocument> scoredDocuments = results.getResults();
// System.out.println("-------------------------------");
// System.out.println("queryString = " + queryString);
// System.out.println("scoredDocuments = " + scoredDocuments);
// for (ScoredDocument scoredDocument : scoredDocuments) {
// System.out.println("scoredDocument = " + scoredDocument);
// }
assertEquals("number of found documents", documentIds.length, results.getNumberFound());
assertEquals("number of returned documents", documentIds.length, results.getNumberReturned());
assertEquals("actual number of ScoredDcuments", documentIds.length, scoredDocuments.size());
Set<String> expectedDocumentIds = new HashSet<String>(Arrays.asList(documentIds));
for (ScoredDocument scoredDocument : scoredDocuments) {
boolean wasContained = expectedDocumentIds.remove(scoredDocument.getId());
if (!wasContained) {
fail("Search \"" + queryString + "\" yielded unexpected document id: " + scoredDocument.getId());
}
}
}
private Index getTestIndex() {
return getIndex("testIndex");
}
private Index getIndex(String name) {
IndexSpec indexSpec = getIndexSpec(name);
return service.getIndex(indexSpec);
}
private IndexSpec getIndexSpec(String name) {
return IndexSpec.newBuilder().setName(name).build();
}
private Field.Builder newField(String fieldName) {
return Field.newBuilder().setName(fieldName);
}
private Document newEmptyDocument() {
return Document.newBuilder().build();
}
private Document newDocument(Field.Builder... fields) {
return newDocument(null, fields);
}
private Document newDocument(String id, Field.Builder... fields) {
Document.Builder builder = Document.newBuilder();
if (id != null) {
builder.setId(id);
}
for (Field.Builder field : fields) {
builder.addField(field);
}
return builder.build();
}
private List<Document> getAllDocumentsIn(Index index) {
return index.getRange(defaultGetRequest()).getResults();
}
protected GetRequest defaultGetRequest() {
return GetRequest.newBuilder().build();
}
private void clear() {
GetResponse<Index> response = service.getIndexes(GetIndexesRequest.newBuilder());
for (Index index : response.getResults()) {
GetResponse<Document> documents = index.getRange(GetRequest.newBuilder());
for (Document document : documents.getResults()) {
index.delete(document.getId());
}
}
}
private void waitForSync() {
sync();
}
}