package com.lordofthejars.nosqlunit.couchbase; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.view.DefaultView; import com.couchbase.client.java.view.DesignDocument; import com.couchbase.client.java.view.Stale; import com.couchbase.client.java.view.View; import com.couchbase.client.java.view.ViewQuery; import com.couchbase.client.java.view.ViewResult; import com.lordofthejars.nosqlunit.core.FailureHandler; import com.lordofthejars.nosqlunit.couchbase.model.Document; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.StreamSupport; import static com.lordofthejars.nosqlunit.util.DeepEquals.deepEquals; public class CouchbaseAssertion { private static final Logger LOGGER = LoggerFactory.getLogger(CouchbaseAssertion.class); private static final String DESIGN_DOC_INTERNAL = "__design_doc_internal_"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static void strictAssertEquals(final InputStream dataset, final Bucket bucket) { final Map<String, Document> expectedDocuments = DataLoader.getDocuments(dataset); final List<String> allDocumentIds = getAllDocumentIds(bucket); checkNumberOfDocuments(expectedDocuments, allDocumentIds); checkEachDocument(expectedDocuments, allDocumentIds, bucket); } private static void checkEachDocument(final Map<String, Document> expectedDocuments, final List<String> allDocumentIds, final Bucket bucket) { for (final String id : allDocumentIds) { final Object real = bucket.get(id); final Object expected = toJson(expectedDocuments.get(id).getDocument()); if (!deepEquals(real, expected)) { throw FailureHandler.createFailure( "Expected element # %s # is not found but # %s # was found.", toJson(expected), toJson(real)); } } } private static String toJson(final Object document) { try { return OBJECT_MAPPER.writeValueAsString(document); } catch (JsonGenerationException e) { throw new IllegalArgumentException(e); } catch (JsonMappingException e) { throw new IllegalArgumentException(e); } catch (IOException e) { throw new IllegalArgumentException(e); } } private static void checkNumberOfDocuments(final Map<String, Document> expectedDocuments, final List<String> allDocumentIds) { final int expectedSize = expectedDocuments.size(); final int currentSize = allDocumentIds.size(); if (expectedSize != currentSize) { throw FailureHandler.createFailure("Expected number of elements are %s but insert are %s. DB document IDS: %s", expectedSize, currentSize, allDocumentIds); } } private static List<String> getAllDocumentIds(final Bucket bucket) { final String freeDesignDocName = nextUniqueViewName(bucket); try { final DesignDocument designDocAndView = createDesignDocAndView(freeDesignDocName, bucket); final List<String> result = getAllDocumentIds(designDocAndView, bucket); return result; } finally { deleteDesignDoc(freeDesignDocName, bucket); } } private static List<String> getAllDocumentIds(final DesignDocument designDocument, final Bucket bucket) { final ViewQuery query = ViewQuery.from(designDocument.name(), designDocument.views().get(0).name()); query.stale(Stale.FALSE); final ViewResult result = bucket.query(query); return StreamSupport.stream(result.spliterator(), true).map(r -> r.id()).collect(Collectors.toList()); } private static DesignDocument createDesignDocAndView(final String freeDesignDocName, final Bucket bucket) { final String json = "function (doc, meta) {" + System.lineSeparator() + " emit(null, null);" + System.lineSeparator() + "}"; final List<View> views = Arrays.asList(DefaultView.create("allDocs", json)); final DesignDocument designDocument = DesignDocument.create(freeDesignDocName, views); bucket.bucketManager().insertDesignDocument(designDocument); return designDocument; } private static void deleteDesignDoc(final String freeDesignDocName, final Bucket bucket) { bucket.bucketManager().removeDesignDocument(freeDesignDocName); } private static String nextUniqueViewName(final Bucket bucket) { int i = 0; while (true) { final String proposal = (DESIGN_DOC_INTERNAL + (i++)); final DesignDocument designDocument = bucket.bucketManager().getDesignDocument(proposal); if (designDocument == null) { return proposal; } LOGGER.trace("Invalid doc, keep trying. Now trying with {} " + proposal); } } }