// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.documentapi.test;
import com.yahoo.document.Document;
import com.yahoo.document.DocumentId;
import com.yahoo.document.DocumentPut;
import com.yahoo.document.DocumentRemove;
import com.yahoo.document.DocumentType;
import com.yahoo.documentapi.AsyncParameters;
import com.yahoo.documentapi.AsyncSession;
import com.yahoo.documentapi.DocumentAccess;
import com.yahoo.documentapi.DocumentResponse;
import com.yahoo.documentapi.Response;
import com.yahoo.documentapi.ResponseHandler;
import com.yahoo.documentapi.Result;
import com.yahoo.documentapi.SyncParameters;
import com.yahoo.documentapi.SyncSession;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* These tests should work with all implementations (who choose to implement these features) To test a certain
* implementation subclass this test and make the subclass setup assign the implementation class to the
* access
member variable (make sure it also calls super.setUp()). Override tests of nonsupported features
* to do nothing.
*
* @author bratseth
*/
public abstract class AbstractDocumentApiTestCase {
protected abstract DocumentAccess access();
@Test
public void requireThatSyncSessionWorks() {
SyncSession session = access().createSyncSession(new SyncParameters.Builder().build());
DocumentType type = access().getDocumentTypeManager().getDocumentType("music");
Document doc1 = new Document(type, new DocumentId("id:ns:music::1"));
Document doc2 = new Document(type, new DocumentId("id:ns:music::2"));
session.put(new DocumentPut(doc1));
session.put(new DocumentPut(doc2));
assertEquals(doc1, session.get(new DocumentId("id:ns:music::1")));
assertEquals(doc2, session.get(new DocumentId("id:ns:music::2")));
session.remove(new DocumentRemove(new DocumentId("id:ns:music::1")));
assertNull(session.get(new DocumentId("id:ns:music::1")));
assertEquals(doc2, session.get(new DocumentId("id:ns:music::2")));
session.remove(new DocumentRemove(new DocumentId("id:ns:music::2")));
assertNull(session.get(new DocumentId("id:ns:music::1")));
assertNull(session.get(new DocumentId("id:ns:music::2")));
session.destroy();
}
@Test
public void requireThatAsyncSessionWorks() throws InterruptedException {
AsyncSession session = access().createAsyncSession(new AsyncParameters());
HashMap results = new LinkedHashMap<>();
Result result;
DocumentType type = access().getDocumentTypeManager().getDocumentType("music");
Document doc1 = new Document(type, new DocumentId("id:ns:music::1"));
Document doc2 = new Document(type, new DocumentId("id:ns:music::2"));
result = session.put(doc1);
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new Response(result.getRequestId()));
result = session.put(doc2);
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new Response(result.getRequestId()));
List responses = new ArrayList<>();
waitForAcks(session, 2, responses);
result = session.get(new DocumentId("id:ns:music::1"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId(), doc1));
result = session.get(new DocumentId("id:ns:music::2"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId(), doc2));
// These Gets shall observe the ACKed Puts sent for the same document IDs.
waitForAcks(session, 2, responses);
result = session.remove(new DocumentId("id:ns:music::1"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new Response(result.getRequestId()));
waitForAcks(session, 1, responses);
result = session.get(new DocumentId("id:ns:music::1"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId()));
result = session.get(new DocumentId("id:ns:music::2"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId(), doc2));
waitForAcks(session, 2, responses);
result = session.remove(new DocumentId("id:ns:music::2"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new Response(result.getRequestId()));
waitForAcks(session, 1, responses);
result = session.get(new DocumentId("id:ns:music::1"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId()));
result = session.get(new DocumentId("id:ns:music::2"));
assertTrue(result.isSuccess());
results.put(result.getRequestId(), new DocumentResponse(result.getRequestId()));
waitForAcks(session, 2, responses);
for (Response response : responses) {
assertTrue(response.isSuccess());
assertEquals(results.get(response.getRequestId()), response);
}
session.destroy();
}
@Test
public void requireThatAsyncHandlerWorks() throws InterruptedException {
MyHandler handler = new MyHandler();
AsyncSession session = access().createAsyncSession(new AsyncParameters().setResponseHandler(handler));
DocumentType type = access().getDocumentTypeManager().getDocumentType("music");
Document doc1 = new Document(type, new DocumentId("id:ns:music::1"));
assertTrue(session.put(doc1).isSuccess());
assertTrue(handler.latch.await(60, TimeUnit.SECONDS));
assertNotNull(handler.response);
session.destroy();
}
private static void waitForAcks(AsyncSession session, int n, List responsesOut) throws InterruptedException {
for (int i = 0; i < n; ++i) {
Response response;
if (i % 2 == 0) {
response = pollNext(session);
} else {
response = session.getNext(60000);
}
responsesOut.add(response);
}
}
private static Response pollNext(AsyncSession session) throws InterruptedException {
for (int i = 0; i < 600; ++i) {
Response response = session.getNext();
if (response != null) {
return response;
}
Thread.sleep(100);
}
return null;
}
private static class MyHandler implements ResponseHandler {
final CountDownLatch latch = new CountDownLatch(1);
Response response = null;
@Override
public void handleResponse(Response response) {
this.response = response;
latch.countDown();
}
}
}