metron-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From o...@apache.org
Subject [25/51] [abbrv] metron git commit: METRON-1771 Update REST endpoints to support eventually consistent UI updates (merrimanr) closes apache/metron#1190
Date Wed, 24 Oct 2018 15:04:14 GMT
http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java
index 4d48075..096baf1 100644
--- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java
+++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDao.java
@@ -24,16 +24,17 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
 import org.apache.metron.common.Constants;
-import org.apache.metron.common.configuration.ConfigurationsUtils;
 import org.apache.metron.indexing.dao.RetrieveLatestDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
@@ -80,15 +81,16 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
    * @param retrieveLatestDao DAO to retrieve the item to be patched
    * @param request The patch request.
    * @param timestamp Optionally a timestamp to set. If not specified then current time is used.
+   * @return The patched document
    * @throws OriginalNotFoundException If no original document is found to patch.
    * @throws IOException If an error occurs performing the patch.
    */
   @Override
-  public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
+  public Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
       Optional<Long> timestamp)
       throws OriginalNotFoundException, IOException {
     if (isPatchAllowed(request)) {
-      updateDao.patch(retrieveLatestDao, request, timestamp);
+      return updateDao.patch(retrieveLatestDao, request, timestamp);
     } else {
       throw new IllegalArgumentException(
           "Meta alert patches are not allowed for /alert or /status paths.  "
@@ -97,7 +99,7 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
   }
 
   @Override
-  public void batchUpdate(Map<Document, Optional<String>> updates) {
+  public Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) {
     throw new UnsupportedOperationException("Meta alerts do not allow for bulk updates");
   }
 
@@ -170,21 +172,65 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
     return updates;
   }
 
+  /**
+   * Adds alerts to a metaalert, based on a list of GetRequests provided for retrieval.
+   * @param metaAlertGuid The GUID of the metaalert to be given new children.
+   * @param alertRequests GetRequests for the appropriate alerts to add.
+   * @return The updated metaalert with alerts added.
+   */
+  @Override
+  public Document addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
+          throws IOException {
+    Document metaAlert = retrieveLatestDao
+            .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE);
+    if (metaAlert == null) {
+      throw new IOException(String.format("Unable to add alerts to meta alert.  Meta alert with guid %s cannot be found.",
+              metaAlertGuid));
+    }
+    if (MetaAlertStatus.ACTIVE.getStatusString()
+            .equals(metaAlert.getDocument().get(MetaAlertConstants.STATUS_FIELD))) {
+      Iterable<Document> alerts = retrieveLatestDao.getAllLatest(alertRequests);
+      Set<String> missingAlerts = getMissingAlerts(alertRequests, alerts);
+      if (!missingAlerts.isEmpty()) {
+        throw new IOException(String.format("Unable to add alerts to meta alert.  Alert with guid %s cannot be found.",
+                missingAlerts.iterator().next()));
+      }
+      Map<Document, Optional<String>> updates = buildAddAlertToMetaAlertUpdates(metaAlert, alerts);
+      update(updates);
+      return metaAlert;
+    } else {
+      throw new IllegalStateException("Adding alerts to an INACTIVE meta alert is not allowed");
+    }
+  }
+
+  /**
+   * Removes alerts from a metaalert, based on a list of GetRequests provided for retrieval.
+   * @param metaAlertGuid The GUID of the metaalert to remove children from.
+   * @param alertRequests A list of GetReqests that will provide the alerts to remove
+   * @return The updated metaalert with alerts removed.
+   * @throws IllegalStateException If the metaalert is inactive.
+   */
   @Override
   @SuppressWarnings("unchecked")
-  public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
-      throws IOException {
+  public Document removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
+      throws IOException, IllegalStateException {
     Document metaAlert = retrieveLatestDao
         .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE);
     if (metaAlert == null) {
-      return false;
+      throw new IOException(String.format("Unable to remove alerts from meta alert.  Meta alert with guid %s cannot be found.",
+              metaAlertGuid));
     }
     if (MetaAlertStatus.ACTIVE.getStatusString()
         .equals(metaAlert.getDocument().get(MetaAlertConstants.STATUS_FIELD))) {
       Iterable<Document> alerts = retrieveLatestDao.getAllLatest(alertRequests);
+      Set<String> missingAlerts = getMissingAlerts(alertRequests, alerts);
+      if (!missingAlerts.isEmpty()) {
+        throw new IOException(String.format("Unable to remove alerts from meta alert.  Alert with guid %s cannot be found.",
+                missingAlerts.iterator().next()));
+      }
       Map<Document, Optional<String>> updates = buildRemoveAlertsFromMetaAlert(metaAlert, alerts);
       update(updates);
-      return updates.size() != 0;
+      return metaAlert;
     } else {
       throw new IllegalStateException("Removing alerts from an INACTIVE meta alert is not allowed");
     }
@@ -213,10 +259,14 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
   }
 
   @Override
-  public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
+  public Document updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
       throws IOException {
     Document metaAlert = retrieveLatestDao
         .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE);
+    if (metaAlert == null) {
+      throw new IOException(String.format("Unable to update meta alert status.  Meta alert with guid %s cannot be found.",
+              metaAlertGuid));
+    }
     String currentStatus = (String) metaAlert.getDocument().get(MetaAlertConstants.STATUS_FIELD);
     boolean metaAlertUpdated = !status.getStatusString().equals(currentStatus);
     if (metaAlertUpdated) {
@@ -231,7 +281,7 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
       Map<Document, Optional<String>> updates = buildStatusChangeUpdates(metaAlert, alerts, status);
       update(updates);
     }
-    return metaAlertUpdated;
+    return metaAlert;
   }
 
   /**
@@ -334,4 +384,13 @@ public abstract class AbstractLuceneMetaAlertUpdateDao implements MetaAlertUpdat
     } // else we have no updates, so don't do anything
   }
 
+  protected Set<String> getMissingAlerts(List<GetRequest> alertRequests, Iterable<Document> results) throws IOException {
+    Set<String> requestGuids = alertRequests.stream().map(GetRequest::getGuid).collect(Collectors.toSet());
+    Set<String> resultGuids = StreamSupport.stream(results.spliterator(), false)
+            .map(Document::getGuid).collect(Collectors.toSet());
+    Set<String> missingGuids = new HashSet<>(requestGuids);
+    missingGuids.removeAll(resultGuids);
+    return missingGuids;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java
index b5f38e4..8f6f6b0 100644
--- a/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java
+++ b/metron-platform/metron-indexing/src/main/java/org/apache/metron/indexing/dao/update/UpdateDao.java
@@ -18,7 +18,6 @@
 package org.apache.metron.indexing.dao.update;
 
 import java.io.IOException;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 import org.apache.metron.common.utils.JSONUtils;
@@ -33,25 +32,27 @@ public interface UpdateDao {
    *
    * @param update The document to replace from the index.
    * @param index The index where the document lives.
+   * @return The updated document
    * @throws IOException If an error occurs during the update.
    */
-  void update(Document update, Optional<String> index) throws IOException;
+  Document update(Document update, Optional<String> index) throws IOException;
 
   /**
    * Similar to the update method but accepts multiple documents and performs updates in batch.
    *
    * @param updates A map of the documents to update to the index where they live.
+   * @return The updated documents.
    * @throws IOException If an error occurs during the updates.
    */
-  void batchUpdate(Map<Document, Optional<String>> updates) throws IOException;
+  Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) throws IOException;
 
-  void addCommentToAlert(CommentAddRemoveRequest request) throws IOException;
+  Document addCommentToAlert(CommentAddRemoveRequest request) throws IOException;
 
-  void removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException;
+  Document removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException;
 
-  void addCommentToAlert(CommentAddRemoveRequest request, Document latest) throws IOException;
+  Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) throws IOException;
 
-  void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) throws IOException;
+  Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) throws IOException;
 
 
   /**
@@ -59,14 +60,15 @@ public interface UpdateDao {
    * https://tools.ietf.org/html/rfc6902)
    * @param request The patch request
    * @param timestamp Optionally a timestamp to set. If not specified then current time is used.
+   * @return The patched document.
    * @throws OriginalNotFoundException If the original is not found, then it cannot be patched.
    * @throws IOException If an error occurs while patching.
    */
-  default void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request
+  default Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request
       , Optional<Long> timestamp
   ) throws OriginalNotFoundException, IOException {
     Document d = getPatchedDocument(retrieveLatestDao, request, timestamp);
-    update(d, Optional.ofNullable(request.getIndex()));
+    return update(d, Optional.ofNullable(request.getIndex()));
   }
 
   default Document getPatchedDocument(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
@@ -94,15 +96,16 @@ public interface UpdateDao {
    * Replace a document in an index.
    * @param request The replacement request.
    * @param timestamp The timestamp (optional) of the update.  If not specified, then current time will be used.
+   * @return The replaced document.
    * @throws IOException If an error occurs during replacement.
    */
-  default void replace(ReplaceRequest request, Optional<Long> timestamp)
+  default Document replace(ReplaceRequest request, Optional<Long> timestamp)
       throws IOException {
     Document d = new Document(request.getReplacement(),
         request.getGuid(),
         request.getSensorType(),
         timestamp.orElse(System.currentTimeMillis())
     );
-    update(d, Optional.ofNullable(request.getIndex()));
+    return update(d, Optional.ofNullable(request.getIndex()));
   }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/InMemoryMetaAlertRetrieveLatestDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/InMemoryMetaAlertRetrieveLatestDao.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/InMemoryMetaAlertRetrieveLatestDao.java
new file mode 100644
index 0000000..28891d9
--- /dev/null
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/InMemoryMetaAlertRetrieveLatestDao.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.metron.indexing;
+
+import org.apache.metron.indexing.dao.IndexDao;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertRetrieveLatestDao;
+import org.apache.metron.indexing.dao.search.GetRequest;
+import org.apache.metron.indexing.dao.update.Document;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This class is needed to compose an InMemoryMetaAlertUpdateDao implementation.  This allows the
+ * InMemoryMetaAlertUpdateDao class to extend AbstractLuceneMetaAlertUpdateDao and reuse common logic in that class.
+ */
+public class InMemoryMetaAlertRetrieveLatestDao implements MetaAlertRetrieveLatestDao {
+
+  private IndexDao indexDao;
+
+  public InMemoryMetaAlertRetrieveLatestDao(IndexDao indexDao) {
+    this.indexDao = indexDao;
+  }
+
+  @Override
+  public Document getLatest(String guid, String sensorType) throws IOException {
+    return indexDao.getLatest(guid, sensorType);
+  }
+
+  @Override
+  public Iterable<Document> getAllLatest(List<GetRequest> getRequests) throws IOException {
+    return indexDao.getAllLatest(getRequests);
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/HBaseDaoTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/HBaseDaoTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/HBaseDaoTest.java
new file mode 100644
index 0000000..d4823db
--- /dev/null
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/HBaseDaoTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.indexing.dao;
+
+import org.apache.metron.indexing.dao.update.UpdateDao;
+import org.junit.Before;
+
+/**
+ * This class returns the HBaseDao implementation to be used in UpdateDaoTest.  UpdateDaoTest contains a
+ * common set of tests that all Dao implementations must pass.
+ */
+public class HBaseDaoTest extends UpdateDaoTest{
+
+  private HBaseDao dao;
+
+  @Before
+  public void setup() {
+    dao = new HBaseDao();
+  }
+
+  @Override
+  public UpdateDao getUpdateDao() {
+    return dao;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryDao.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryDao.java
index e306567..f49a6ad 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryDao.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryDao.java
@@ -248,7 +248,7 @@ public class InMemoryDao implements IndexDao {
   }
 
   @Override
-  public void update(Document update, Optional<String> index) throws IOException {
+  public Document update(Document update, Optional<String> index) throws IOException {
     for (Map.Entry<String, List<String>> kv : BACKING_STORE.entrySet()) {
       if (kv.getKey().startsWith(update.getSensorType())) {
         for (Iterator<String> it = kv.getValue().iterator(); it.hasNext(); ) {
@@ -261,13 +261,15 @@ public class InMemoryDao implements IndexDao {
         kv.getValue().add(JSONUtils.INSTANCE.toJSON(update.getDocument(), true));
       }
     }
+    return update;
   }
 
   @Override
-  public void batchUpdate(Map<Document, Optional<String>> updates) throws IOException {
+  public Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) throws IOException {
     for (Map.Entry<Document, Optional<String>> update : updates.entrySet()) {
       update(update.getKey(), update.getValue());
     }
+    return updates;
   }
 
   @Override
@@ -293,19 +295,23 @@ public class InMemoryDao implements IndexDao {
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request) {
+  public Document addCommentToAlert(CommentAddRemoveRequest request) {
+    return null;
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request) {
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) {
+    return null;
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+    return null;
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+    return null;
   }
 
   public static void setColumnMetadata(Map<String, Map<String, FieldType>> columnMetadata) {

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java
index cb8837b..dbd3cb6 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertDao.java
@@ -18,26 +18,24 @@
 
 package org.apache.metron.indexing.dao;
 
-import static org.apache.metron.common.Constants.GUID;
+import static org.apache.metron.common.Constants.SENSOR_TYPE;
 
-import com.google.common.collect.ImmutableList;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
+import java.util.function.Supplier;
 import org.adrianwalker.multilinestring.Multiline;
 import org.apache.metron.common.utils.JSONUtils;
+import org.apache.metron.indexing.InMemoryMetaAlertRetrieveLatestDao;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest;
-import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertDao;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertRetrieveLatestDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus;
-import org.apache.metron.indexing.dao.metaalert.MetaScores;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertUpdateDao;
 import org.apache.metron.indexing.dao.search.FieldType;
 import org.apache.metron.indexing.dao.search.GetRequest;
 import org.apache.metron.indexing.dao.search.GroupRequest;
@@ -46,20 +44,19 @@ import org.apache.metron.indexing.dao.search.InvalidCreateException;
 import org.apache.metron.indexing.dao.search.InvalidSearchException;
 import org.apache.metron.indexing.dao.search.SearchRequest;
 import org.apache.metron.indexing.dao.search.SearchResponse;
-import org.apache.metron.indexing.dao.search.SearchResult;
 import org.apache.metron.indexing.dao.update.CommentAddRemoveRequest;
 import org.apache.metron.indexing.dao.update.Document;
 import org.apache.metron.indexing.dao.update.OriginalNotFoundException;
 import org.apache.metron.indexing.dao.update.PatchRequest;
 import org.apache.metron.indexing.dao.update.ReplaceRequest;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
 
 public class InMemoryMetaAlertDao implements MetaAlertDao {
 
-  public static Map<String, Collection<String>> METAALERT_STORE = new HashMap<>();
+  public static final String METAALERT_INDEX = "metaalert_index";
 
   private IndexDao indexDao;
+  private MetaAlertRetrieveLatestDao metaAlertRetrieveLatestDao;
+  private MetaAlertUpdateDao metaAlertUpdateDao;
   private int pageSize = 10;
 
   /**
@@ -97,6 +94,24 @@ public class InMemoryMetaAlertDao implements MetaAlertDao {
   @Override
   public void init(IndexDao indexDao, Optional<String> threatSort) {
     this.indexDao = indexDao;
+    this.metaAlertRetrieveLatestDao = new InMemoryMetaAlertRetrieveLatestDao(indexDao);
+    Supplier<Map<String, Object>> globalConfigSupplier = () -> new HashMap<>();
+    MetaAlertConfig config = new MetaAlertConfig(
+            METAALERT_INDEX,
+            null,
+            globalConfigSupplier
+    ) {
+      @Override
+      protected String getDefaultThreatTriageField() {
+        return MetaAlertConstants.THREAT_FIELD_DEFAULT;
+      }
+
+      @Override
+      protected String getDefaultSourceTypeField() {
+        return SENSOR_TYPE;
+      }
+    };
+    this.metaAlertUpdateDao = new InMemoryMetaAlertUpdateDao(indexDao, metaAlertRetrieveLatestDao, config, -1);
     // Ignore threatSort for test.
   }
 
@@ -112,12 +127,12 @@ public class InMemoryMetaAlertDao implements MetaAlertDao {
   }
 
   @Override
-  public void update(Document update, Optional<String> index) throws IOException {
-    indexDao.update(update, index);
+  public Document update(Document update, Optional<String> index) throws IOException {
+    return indexDao.update(update, index);
   }
 
   @Override
-  public void batchUpdate(Map<Document, Optional<String>> updates) {
+  public Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) {
     throw new UnsupportedOperationException("InMemoryMetaAlertDao can't do bulk updates");
   }
 
@@ -128,19 +143,23 @@ public class InMemoryMetaAlertDao implements MetaAlertDao {
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request) {
+  public Document addCommentToAlert(CommentAddRemoveRequest request) {
+    return null;
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request) {
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) {
+    return null;
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+    return null;
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+    return null;
   }
 
   @Override
@@ -149,15 +168,15 @@ public class InMemoryMetaAlertDao implements MetaAlertDao {
   }
 
   @Override
-  public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
+  public Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
       Optional<Long> timestamp)
       throws OriginalNotFoundException, IOException {
-    indexDao.patch(retrieveLatestDao, request, timestamp);
+    return indexDao.patch(retrieveLatestDao, request, timestamp);
   }
 
   @Override
-  public void replace(ReplaceRequest request, Optional<Long> timestamp) throws IOException {
-    indexDao.replace(request, timestamp);
+  public Document replace(ReplaceRequest request, Optional<Long> timestamp) throws IOException {
+    return indexDao.replace(request, timestamp);
   }
 
   @Override
@@ -174,145 +193,29 @@ public class InMemoryMetaAlertDao implements MetaAlertDao {
 
   @SuppressWarnings("unchecked")
   @Override
-  public MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request)
-      throws InvalidCreateException {
-    List<GetRequest> alertRequests = request.getAlerts();
-    if (alertRequests.isEmpty()) {
-      MetaAlertCreateResponse response = new MetaAlertCreateResponse();
-      response.setCreated(false);
-      return response;
-    }
-    // Build meta alert json.  Give it a reasonable GUID
-    JSONObject metaAlert = new JSONObject();
-    String metaAlertGuid =
-        "meta_" + (InMemoryDao.BACKING_STORE.get(getMetaAlertIndex()).size() + 1);
-    metaAlert.put(GUID, metaAlertGuid);
-
-    JSONArray groupsArray = new JSONArray();
-    groupsArray.addAll(request.getGroups());
-    metaAlert.put(MetaAlertConstants.GROUPS_FIELD, groupsArray);
-
-    // Retrieve the alert for each guid
-    // For the purpose of testing, we're just using guids for the alerts field and grabbing the scores.
-    JSONArray alertArray = new JSONArray();
-    List<Double> threatScores = new ArrayList<>();
-    Collection<String> alertGuids = new ArrayList<>();
-    for (GetRequest alertRequest : alertRequests) {
-      SearchRequest searchRequest = new SearchRequest();
-      searchRequest.setIndices(ImmutableList.of(alertRequest.getIndex().get()));
-      searchRequest.setQuery("guid:" + alertRequest.getGuid());
-      try {
-        SearchResponse searchResponse = search(searchRequest);
-        List<SearchResult> searchResults = searchResponse.getResults();
-        if (searchResults.size() > 1) {
-          throw new InvalidCreateException(
-              "Found more than one result for: " + alertRequest.getGuid() + ". Values: "
-                  + searchResults
-          );
-        }
-
-        if (searchResults.size() == 1) {
-          SearchResult result = searchResults.get(0);
-          alertArray.add(result.getSource());
-          Double threatScore = Double
-              .parseDouble(
-                  result.getSource().getOrDefault(MetaAlertConstants.THREAT_FIELD_DEFAULT, "0")
-                      .toString());
-
-          threatScores.add(threatScore);
-        }
-      } catch (InvalidSearchException e) {
-        throw new InvalidCreateException("Unable to find guid: " + alertRequest.getGuid(), e);
-      }
-      alertGuids.add(alertRequest.getGuid());
-    }
-
-    metaAlert.put(MetaAlertConstants.ALERT_FIELD, alertArray);
-    metaAlert.putAll(new MetaScores(threatScores).getMetaScores());
-    metaAlert.put(MetaAlertConstants.STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString());
-
-    // Add the alert to the store, but make sure not to overwrite existing results
-    InMemoryDao.BACKING_STORE.get(getMetaAlertIndex()).add(metaAlert.toJSONString());
-
-    METAALERT_STORE.put(metaAlertGuid, new HashSet<>(alertGuids));
-
-    MetaAlertCreateResponse createResponse = new MetaAlertCreateResponse();
-    createResponse.setGuid(metaAlertGuid);
-    createResponse.setCreated(true);
-    return createResponse;
+  public Document createMetaAlert(MetaAlertCreateRequest request)
+      throws InvalidCreateException, IOException {
+    return metaAlertUpdateDao.createMetaAlert(request);
   }
 
   @Override
-  public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) {
-    Collection<String> currentAlertGuids = METAALERT_STORE.get(metaAlertGuid);
-    if (currentAlertGuids == null) {
-      return false;
-    }
-    Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid)
-        .collect(Collectors.toSet());
-    boolean added = currentAlertGuids.addAll(alertGuids);
-    if (added) {
-      METAALERT_STORE.put(metaAlertGuid, currentAlertGuids);
-    }
-    return added;
+  public Document addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) throws IOException {
+    return metaAlertUpdateDao.addAlertsToMetaAlert(metaAlertGuid, alertRequests);
   }
 
   @Override
-  public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) {
-    Collection<String> currentAlertGuids = METAALERT_STORE.get(metaAlertGuid);
-    if (currentAlertGuids == null) {
-      return false;
-    }
-    Collection<String> alertGuids = alertRequests.stream().map(GetRequest::getGuid)
-        .collect(Collectors.toSet());
-    boolean removed = currentAlertGuids.removeAll(alertGuids);
-    if (removed) {
-      METAALERT_STORE.put(metaAlertGuid, currentAlertGuids);
-    }
-    return removed;
+  public Document removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) throws IOException {
+    return metaAlertUpdateDao.removeAlertsFromMetaAlert(metaAlertGuid, alertRequests);
   }
 
   @SuppressWarnings("unchecked")
   @Override
-  public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
+  public Document updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
       throws IOException {
-    boolean statusChanged = false;
-    List<String> metaAlerts = InMemoryDao.BACKING_STORE.get(getMetaAlertIndex());
-    for (String metaAlert : metaAlerts) {
-      JSONObject metaAlertJSON = JSONUtils.INSTANCE.load(metaAlert, JSONObject.class);
-      if (metaAlertGuid.equals(metaAlertJSON.get(GUID))) {
-        statusChanged = !status.getStatusString()
-            .equals(metaAlertJSON.get(MetaAlertConstants.STATUS_FIELD));
-        if (statusChanged) {
-          metaAlertJSON.put(MetaAlertConstants.STATUS_FIELD, status.getStatusString());
-          metaAlerts.remove(metaAlert);
-          metaAlerts.add(metaAlertJSON.toJSONString());
-          InMemoryDao.BACKING_STORE.put(getMetaAlertIndex(), metaAlerts);
-        }
-        break;
-      }
-    }
-    return statusChanged;
-  }
-
-  public int getPageSize() {
-    return pageSize;
-  }
-
-  public void setPageSize(int pageSize) {
-    this.pageSize = pageSize;
-  }
-
-  public String getMetAlertSensorName() {
-    return MetaAlertConstants.METAALERT_TYPE;
-  }
-
-  public String getMetaAlertIndex() {
-    return "metaalert_index";
+    return metaAlertUpdateDao.updateMetaAlertStatus(metaAlertGuid, status);
   }
 
   public static void clear() {
     InMemoryDao.clear();
-    METAALERT_STORE.clear();
   }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertUpdateDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertUpdateDao.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertUpdateDao.java
new file mode 100644
index 0000000..53564b0
--- /dev/null
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/InMemoryMetaAlertUpdateDao.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.metron.indexing.dao;
+
+import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest;
+import org.apache.metron.indexing.dao.metaalert.MetaAlertRetrieveLatestDao;
+import org.apache.metron.indexing.dao.metaalert.lucene.AbstractLuceneMetaAlertUpdateDao;
+import org.apache.metron.indexing.dao.search.GetRequest;
+import org.apache.metron.indexing.dao.search.InvalidCreateException;
+import org.apache.metron.indexing.dao.update.CommentAddRemoveRequest;
+import org.apache.metron.indexing.dao.update.Document;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+
+public class InMemoryMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao {
+
+  private IndexDao indexDao;
+
+  public InMemoryMetaAlertUpdateDao(
+          IndexDao indexDao,
+          MetaAlertRetrieveLatestDao retrieveLatestDao,
+          MetaAlertConfig config,
+          int pageSize
+  ) {
+    super(indexDao, retrieveLatestDao, config);
+    this.indexDao = indexDao;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Document createMetaAlert(MetaAlertCreateRequest request) throws InvalidCreateException, IOException {
+    List<GetRequest> alertRequests = request.getAlerts();
+    if (alertRequests.isEmpty()) {
+      return null;
+    }
+    // Retrieve the documents going into the meta alert and build it
+    Iterable<Document> alerts = indexDao.getAllLatest(alertRequests);
+
+    Document metaAlert = buildCreateDocument(alerts, request.getGroups(),
+            MetaAlertConstants.ALERT_FIELD);
+
+    metaAlert.getDocument()
+            .put(getConfig().getSourceTypeField(), MetaAlertConstants.METAALERT_TYPE);
+
+    return metaAlert;
+  }
+
+  @Override
+  public Document update(Document update, Optional<String> index) throws IOException {
+    return indexDao.update(update, index);
+  }
+
+  @Override
+  public Document addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
+    return null;
+  }
+
+  @Override
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
+    return null;
+  }
+
+  @Override
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
+    return null;
+  }
+
+  @Override
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/MultiIndexDaoTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/MultiIndexDaoTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/MultiIndexDaoTest.java
new file mode 100644
index 0000000..dad6a52
--- /dev/null
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/MultiIndexDaoTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.indexing.dao;
+
+import org.apache.metron.indexing.dao.update.CommentAddRemoveRequest;
+import org.apache.metron.indexing.dao.update.Document;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MultiIndexDaoTest {
+  @Rule
+  public final ExpectedException exception = ExpectedException.none();
+
+  private MultiIndexDao multiIndexDao;
+  private IndexDao dao1;
+  private IndexDao dao2;
+
+  @Before
+  public void setup() {
+    dao1 = mock(IndexDao.class);
+    dao2 = mock(IndexDao.class);
+    multiIndexDao = new MultiIndexDao(dao1, dao2);
+  }
+
+  @Test
+  public void getLatestShouldReturnLatestAlert() throws Exception {
+    Document document1 = new Document(new HashMap<>(), "guid", "bro", 1L);
+    Document document2 = new Document(new HashMap<>(), "guid", "bro", 2L);
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+    when(dao1.getLatest("guid", "bro")).thenReturn(document1);
+    when(dao2.getLatest("guid", "bro")).thenReturn(document2);
+
+
+    Document expected = new Document(new HashMap<>(), "guid", "bro", 2L);
+    Assert.assertEquals(expected, multiIndexDao.getLatest("guid", "bro"));
+  }
+
+  @Test
+  public void addCommentShouldAddCommentToAlert() throws Exception {
+    Document latest = mock(Document.class);
+    Document document1 = new Document(new HashMap<>(), "guid", "bro", 1L);
+    Document document2 = new Document(new HashMap<>(), "guid", "bro", 2L);
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+    when(dao1.addCommentToAlert(request, latest)).thenReturn(document1);
+    when(dao2.addCommentToAlert(request, latest)).thenReturn(document2);
+
+
+    Document expected = new Document(new HashMap<>(), "guid", "bro", 2L);
+    Assert.assertEquals(expected, multiIndexDao.addCommentToAlert(request, latest));
+  }
+
+  @Test
+  public void removeCommentShouldRemoveCommentFromAlert() throws Exception {
+    Document latest = mock(Document.class);
+    Document document1 = new Document(new HashMap<>(), "guid", "bro", 1L);
+    Document document2 = new Document(new HashMap<>(), "guid", "bro", 2L);
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+    when(dao1.removeCommentFromAlert(request, latest)).thenReturn(document1);
+    when(dao2.removeCommentFromAlert(request, latest)).thenReturn(document2);
+
+
+    Document expected = new Document(new HashMap<>(), "guid", "bro", 2L);
+    Assert.assertEquals(expected, multiIndexDao.removeCommentFromAlert(request, latest));
+  }
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateDaoTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateDaoTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateDaoTest.java
new file mode 100644
index 0000000..bbe7fa8
--- /dev/null
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateDaoTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.metron.indexing.dao;
+
+import org.apache.metron.indexing.dao.update.CommentAddRemoveRequest;
+import org.apache.metron.indexing.dao.update.Document;
+import org.apache.metron.indexing.dao.update.UpdateDao;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * The tests in this class are common among all UpdateDao implementations.
+ */
+public abstract class UpdateDaoTest {
+
+  @Rule
+  public final ExpectedException exception = ExpectedException.none();
+
+  @Test
+  public void addCommentShouldThrowExceptionOnMissingAlert() throws Exception {
+    exception.expect(IOException.class);
+    exception.expectMessage("Unable to add comment. Document with guid guid cannot be found.");
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+
+    getUpdateDao().addCommentToAlert(request, null);
+  }
+
+  @Test
+  public void removeCommentShouldThrowExceptionOnMissingAlert() throws Exception {
+    exception.expect(IOException.class);
+    exception.expectMessage("Unable to remove comment. Document with guid guid cannot be found.");
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+
+    getUpdateDao().removeCommentFromAlert(request, null);
+  }
+
+  @Test
+  public void removeCommentShouldThrowExceptionOnEmptyComments() throws Exception {
+    exception.expect(IOException.class);
+    exception.expectMessage("Unable to remove comment. Document with guid guid has no comments.");
+
+    CommentAddRemoveRequest request = new CommentAddRemoveRequest();
+    request.setGuid("guid");
+    Document latest = new Document(new HashMap<>(), "guid", "bro", System.currentTimeMillis());
+
+    getUpdateDao().removeCommentFromAlert(request, latest);
+  }
+
+  public abstract UpdateDao getUpdateDao();
+}

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateIntegrationTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateIntegrationTest.java
index 1e35523..ef9714e 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateIntegrationTest.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/UpdateIntegrationTest.java
@@ -18,7 +18,6 @@ import static org.apache.metron.indexing.dao.IndexDao.COMMENTS_FIELD;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -99,13 +98,14 @@ public abstract class UpdateIntegrationTest {
         put("new-field", "metron");
       }};
       String guid = "" + message0.get(Constants.GUID);
-      getDao().replace(new ReplaceRequest(){{
+      Document update = getDao().replace(new ReplaceRequest(){{
         setReplacement(message0);
         setGuid(guid);
         setSensorType(SENSOR_NAME);
         setIndex(getIndexName());
       }}, Optional.empty());
 
+      Assert.assertEquals(message0, update.getDocument());
       Assert.assertEquals(1, getMockHTable().size());
       findUpdatedDoc(message0, guid, SENSOR_NAME);
       {
@@ -138,12 +138,13 @@ public abstract class UpdateIntegrationTest {
         put("new-field", "metron2");
       }};
       String guid = "" + message0.get(Constants.GUID);
-      getDao().replace(new ReplaceRequest(){{
+      Document update = getDao().replace(new ReplaceRequest(){{
         setReplacement(message0);
         setGuid(guid);
         setSensorType(SENSOR_NAME);
         setIndex(getIndexName());
       }}, Optional.empty());
+      Assert.assertEquals(message0, update.getDocument());
       Assert.assertEquals(1, getMockHTable().size());
       Document doc = getDao().getLatest(guid, SENSOR_NAME);
       Assert.assertEquals(message0, doc.getDocument());
@@ -184,33 +185,40 @@ public abstract class UpdateIntegrationTest {
     fields.put("source.type", SENSOR_NAME);
 
     Document document = new Document(fields, "add_comment", SENSOR_NAME, 1526306463050L);
-    getDao().update(document, Optional.of(SENSOR_NAME));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
-
-    addAlertComment("add_comment", "New Comment", "test_user", 1526306463050L);
-    // Ensure we have the first comment
+    {
+      Document update = getDao().update(document, Optional.of(SENSOR_NAME));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
     ArrayList<AlertComment> comments = new ArrayList<>();
-    comments.add(new AlertComment("New Comment", "test_user", 1526306463050L));
-    document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
-        Collectors.toList()));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
-
-    List<Map<String, Object>> patchList = new ArrayList<>();
-    Map<String, Object> patch = new HashMap<>();
-    patch.put("op", "add");
-    patch.put("path", "/project");
-    patch.put("value", "metron");
-    patchList.add(patch);
+    {
+      Document update = addAlertComment("add_comment", "New Comment", "test_user", 1526306463050L);
+      // Ensure we have the first comment
+      comments.add(new AlertComment("New Comment", "test_user", 1526306463050L));
+      document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
+              Collectors.toList()));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
+    {
+      List<Map<String, Object>> patchList = new ArrayList<>();
+      Map<String, Object> patch = new HashMap<>();
+      patch.put("op", "add");
+      patch.put("path", "/project");
+      patch.put("value", "metron");
+      patchList.add(patch);
 
-    PatchRequest pr = new PatchRequest();
-    pr.setGuid("add_comment");
-    pr.setIndex(SENSOR_NAME);
-    pr.setSensorType(SENSOR_NAME);
-    pr.setPatch(patchList);
-    getDao().patch(getDao(), pr, Optional.of(new Date().getTime()));
+      PatchRequest pr = new PatchRequest();
+      pr.setGuid("add_comment");
+      pr.setIndex(SENSOR_NAME);
+      pr.setSensorType(SENSOR_NAME);
+      pr.setPatch(patchList);
+      Document update = getDao().patch(getDao(), pr, Optional.of(1526306463050L));
 
-    document.getDocument().put("project", "metron");
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+      document.getDocument().put("project", "metron");
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
   }
 
   @Test
@@ -221,48 +229,60 @@ public abstract class UpdateIntegrationTest {
     fields.put("source.type", SENSOR_NAME);
 
     Document document = new Document(fields, "add_comment", SENSOR_NAME, 1526401584951L);
-    getDao().update(document, Optional.of(SENSOR_NAME));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
-
-    addAlertComment("add_comment", "New Comment", "test_user", 1526401584951L);
-    // Ensure we have the first comment
+    {
+      Document update = getDao().update(document, Optional.of(SENSOR_NAME));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
     ArrayList<AlertComment> comments = new ArrayList<>();
-    comments.add(new AlertComment("New Comment", "test_user", 1526401584951L));
-    document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
-        Collectors.toList()));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
-
-    addAlertComment("add_comment", "New Comment 2", "test_user_2", 1526401584952L);
-    // Ensure we have the second comment
-    comments.add(new AlertComment("New Comment 2", "test_user_2", 1526401584952L));
-    document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
-        Collectors.toList()));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
-
-    removeAlertComment("add_comment", "New Comment 2", "test_user_2", 1526401584952L);
-    // Ensure we only have the first comments
-    comments = new ArrayList<>();
-    comments.add(new AlertComment(commentOne));
-    document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
-        Collectors.toList()));
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    {
+      Document update = addAlertComment("add_comment", "New Comment", "test_user", 1526401584951L);
+      // Ensure we have the first comment
 
-    removeAlertComment("add_comment", "New Comment", "test_user", 1526401584951L);
-    // Ensure we have no comments
-    document.getDocument().remove(COMMENTS_FIELD);
-    findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+      comments.add(new AlertComment("New Comment", "test_user", 1526401584951L));
+      document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
+              Collectors.toList()));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
+    {
+      Document update = addAlertComment("add_comment", "New Comment 2", "test_user_2", 1526401584952L);
+      // Ensure we have the second comment
+      comments.add(new AlertComment("New Comment 2", "test_user_2", 1526401584952L));
+      document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
+              Collectors.toList()));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
+    {
+      Document update = removeAlertComment("add_comment", "New Comment 2", "test_user_2", 1526401584952L);
+      // Ensure we only have the first comments
+      comments = new ArrayList<>();
+      comments.add(new AlertComment(commentOne));
+      document.getDocument().put(COMMENTS_FIELD, comments.stream().map(AlertComment::asMap).collect(
+              Collectors.toList()));
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
+    {
+      Document update = removeAlertComment("add_comment", "New Comment", "test_user", 1526401584951L);
+      // Ensure we have no comments
+      document.getDocument().remove(COMMENTS_FIELD);
+      Assert.assertEquals(document, update);
+      findUpdatedDoc(document.getDocument(), "add_comment", SENSOR_NAME);
+    }
   }
 
-  protected void addAlertComment(String guid, String comment, String username, long timestamp)
+  protected Document addAlertComment(String guid, String comment, String username, long timestamp)
       throws IOException {
     CommentAddRemoveRequest request = buildAlertRequest(guid, comment, username, timestamp);
-    getDao().addCommentToAlert(request);
+    return getDao().addCommentToAlert(request);
   }
 
-  protected void removeAlertComment(String guid, String comment, String username, long timestamp)
+  protected Document removeAlertComment(String guid, String comment, String username, long timestamp)
       throws IOException {
     CommentAddRemoveRequest request = buildAlertRequest(guid, comment, username, timestamp);
-    getDao().removeCommentFromAlert(request);
+    return getDao().removeCommentFromAlert(request);
   }
 
   private CommentAddRemoveRequest buildAlertRequest(String guid, String comment, String username,

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/MetaAlertIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/MetaAlertIntegrationTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/MetaAlertIntegrationTest.java
index f754b81..7e28853 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/MetaAlertIntegrationTest.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/MetaAlertIntegrationTest.java
@@ -278,11 +278,40 @@ public abstract class MetaAlertIntegrationTest {
         }});
         setGroups(Collections.singletonList("group"));
       }};
-      MetaAlertCreateResponse metaAlertCreateResponse = metaDao
+
+      Document actualMetaAlert = metaDao
           .createMetaAlert(metaAlertCreateRequest);
+
+      // Build expected metaAlert after alerts are added
+      Map<String, Object> expectedMetaAlert = new HashMap<>();
+
+      expectedMetaAlert.put(Constants.GUID, actualMetaAlert.getGuid());
+      expectedMetaAlert.put(getSourceTypeField(), METAALERT_TYPE);
+      expectedMetaAlert.put(STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString());
+      // Verify the proper alerts were added
+      @SuppressWarnings("unchecked")
+      List<Map<String, Object>> metaAlertAlerts = new ArrayList<>();
+      // Alert 0 is already in the metaalert. Add alerts 1 and 2.
+      Map<String, Object> expectedAlert1 = alerts.get(1);
+      expectedAlert1.put(METAALERT_FIELD, Collections.singletonList(actualMetaAlert.getGuid()));
+      metaAlertAlerts.add(expectedAlert1);
+      Map<String, Object> expectedAlert2 = alerts.get(2);
+      expectedAlert2.put(METAALERT_FIELD, Collections.singletonList(actualMetaAlert.getGuid()));
+      metaAlertAlerts.add(expectedAlert2);
+      expectedMetaAlert.put(ALERT_FIELD, metaAlertAlerts);
+
+      // Verify the counts were properly updated
+      expectedMetaAlert.put("average", 1.5d);
+      expectedMetaAlert.put("min", 1.0d);
+      expectedMetaAlert.put("median", 1.5d);
+      expectedMetaAlert.put("max", 2.0d);
+      expectedMetaAlert.put("count", 2);
+      expectedMetaAlert.put("sum", 3.0d);
+      expectedMetaAlert.put(getThreatTriageField(), 3.0d);
       {
         // Verify metaAlert was created
-        findCreatedDoc(metaAlertCreateResponse.getGuid(), METAALERT_TYPE);
+        assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
+        findCreatedDoc(actualMetaAlert.getGuid(), METAALERT_TYPE);
       }
       {
         // Verify alert 0 was not updated with metaalert field
@@ -294,14 +323,14 @@ public abstract class MetaAlertIntegrationTest {
         // Verify alert 1 was properly updated with metaalert field
         Map<String, Object> expectedAlert = new HashMap<>(alerts.get(1));
         expectedAlert
-            .put(METAALERT_FIELD, Collections.singletonList(metaAlertCreateResponse.getGuid()));
+            .put(METAALERT_FIELD, Collections.singletonList(actualMetaAlert.getGuid()));
         findUpdatedDoc(expectedAlert, "message_1", SENSOR_NAME);
       }
       {
         // Verify alert 2 was properly updated with metaalert field
         Map<String, Object> expectedAlert = new HashMap<>(alerts.get(2));
         expectedAlert
-            .put(METAALERT_FIELD, Collections.singletonList(metaAlertCreateResponse.getGuid()));
+            .put(METAALERT_FIELD, Collections.singletonList(actualMetaAlert.getGuid()));
         findUpdatedDoc(expectedAlert, "message_2", SENSOR_NAME);
       }
     }
@@ -355,17 +384,19 @@ public abstract class MetaAlertIntegrationTest {
 
     {
       // Verify alerts were successfully added to the meta alert
-      Assert.assertTrue(metaDao.addAlertsToMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_1", SENSOR_NAME),
-              new GetRequest("message_2", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.addAlertsToMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_1", SENSOR_NAME),
+                      new GetRequest("message_2", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
 
     {
       // Verify False when alerts are already in a meta alert and no new alerts are added
-      Assert.assertFalse(metaDao.addAlertsToMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_0", SENSOR_NAME),
-              new GetRequest("message_1", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.addAlertsToMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_0", SENSOR_NAME),
+                      new GetRequest("message_1", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
 
@@ -385,9 +416,10 @@ public abstract class MetaAlertIntegrationTest {
       expectedMetaAlert.put("sum", 6.0d);
       expectedMetaAlert.put(getThreatTriageField(), 6.0d);
 
-      Assert.assertTrue(metaDao.addAlertsToMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_2", SENSOR_NAME),
-              new GetRequest("message_3", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.addAlertsToMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_2", SENSOR_NAME),
+                      new GetRequest("message_3", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
   }
@@ -437,17 +469,19 @@ public abstract class MetaAlertIntegrationTest {
 
     {
       // Verify a list of alerts are removed from a meta alert
-      Assert.assertTrue(metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_0", SENSOR_NAME),
-              new GetRequest("message_1", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_0", SENSOR_NAME),
+                      new GetRequest("message_1", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
 
     {
       // Verify False when alerts are not present in a meta alert and no alerts are removed
-      Assert.assertFalse(metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_0", SENSOR_NAME),
-              new GetRequest("message_1", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_0", SENSOR_NAME),
+                      new GetRequest("message_1", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
 
@@ -466,9 +500,10 @@ public abstract class MetaAlertIntegrationTest {
       expectedMetaAlert.put("sum", 3.0d);
       expectedMetaAlert.put(getThreatTriageField(), 3.0d);
 
-      Assert.assertTrue(metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
-          .asList(new GetRequest("message_0", SENSOR_NAME),
-              new GetRequest("message_2", SENSOR_NAME))));
+      Document actualMetaAlert = metaDao.removeAlertsFromMetaAlert("meta_alert", Arrays
+              .asList(new GetRequest("message_0", SENSOR_NAME),
+                      new GetRequest("message_2", SENSOR_NAME)));
+      assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
     }
 
@@ -587,11 +622,11 @@ public abstract class MetaAlertIntegrationTest {
 
     {
       // Verify status changed to inactive and child alerts are updated
-      Assert.assertTrue(metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.INACTIVE));
-
       Map<String, Object> expectedMetaAlert = new HashMap<>(metaAlert);
       expectedMetaAlert.put(STATUS_FIELD, MetaAlertStatus.INACTIVE.getStatusString());
 
+      Document actualMetaAlert = metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.INACTIVE);
+      Assert.assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
 
       for (int i = 0; i < numChildAlerts; ++i) {
@@ -610,11 +645,11 @@ public abstract class MetaAlertIntegrationTest {
 
     {
       // Verify status changed to active and child alerts are updated
-      Assert.assertTrue(metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.ACTIVE));
-
       Map<String, Object> expectedMetaAlert = new HashMap<>(metaAlert);
       expectedMetaAlert.put(STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString());
 
+      Document actualMetaAlert = metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.ACTIVE);
+      Assert.assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
       findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
 
       for (int i = 0; i < numChildAlerts; ++i) {
@@ -629,11 +664,15 @@ public abstract class MetaAlertIntegrationTest {
         // Make sure to handle the guid offset from creation
         findUpdatedDoc(expectedAlert, "message_" + (i + numChildAlerts), SENSOR_NAME);
       }
-
+    }
+    {
       {
         // Verify status changed to current status has no effect
-        Assert.assertFalse(metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.ACTIVE));
+        Map<String, Object> expectedMetaAlert = new HashMap<>(metaAlert);
+        expectedMetaAlert.put(STATUS_FIELD, MetaAlertStatus.ACTIVE.getStatusString());
 
+        Document actualMetaAlert = metaDao.updateMetaAlertStatus("meta_alert", MetaAlertStatus.ACTIVE);
+        Assert.assertEquals(expectedMetaAlert, actualMetaAlert.getDocument());
         findUpdatedDoc(expectedMetaAlert, "meta_alert", METAALERT_TYPE);
 
         for (int i = 0; i < numChildAlerts; ++i) {
@@ -985,6 +1024,30 @@ public abstract class MetaAlertIntegrationTest {
     throw new OriginalNotFoundException("Count not find guids after " + MAX_RETRIES + "tries");
   }
 
+  @SuppressWarnings("unchecked")
+  protected void assertEquals(Map<String, Object> expected, Map<String, Object> actual) {
+    Assert.assertEquals(expected.get(Constants.GUID), actual.get(Constants.GUID));
+    Assert.assertEquals(expected.get(getSourceTypeField()), actual.get(getSourceTypeField()));
+    Double actualThreatTriageField = actual.get(getThreatTriageField()) instanceof Float ?
+            ((Float) actual.get(getThreatTriageField())).doubleValue() : (Double) actual.get(getThreatTriageField());
+    Assert.assertEquals(expected.get(getThreatTriageField()), actualThreatTriageField);
+
+    List<Map<String, Object>> expectedAlerts = (List<Map<String, Object>>) expected.get(ALERT_FIELD);
+    List<Map<String, Object>> actualAlerts = (List<Map<String, Object>>) actual.get(ALERT_FIELD);
+    expectedAlerts.sort(Comparator.comparing(o -> ((String) o.get(Constants.GUID))));
+    actualAlerts.sort(Comparator.comparing(o -> ((String) o.get(Constants.GUID))));
+    Assert.assertEquals(expectedAlerts, actualAlerts);
+    Assert.assertEquals(expected.get(STATUS_FIELD), actual.get(STATUS_FIELD));
+    Assert.assertEquals(expected.get("average"), actual.get("average"));
+    Assert.assertEquals(expected.get("min"), actual.get("min"));
+    Assert.assertEquals(expected.get("median"), actual.get("median"));
+    Assert.assertEquals(expected.get("max"), actual.get("max"));
+    Integer actualCountField = actual.get("count") instanceof Long ? ((Long) actual.get("count")).intValue() :
+            (Integer) actual.get("count");
+    Assert.assertEquals(expected.get("count"), actualCountField);
+    Assert.assertEquals(expected.get("sum"), actual.get("sum"));
+  }
+
   protected List<Map<String, Object>> buildAlerts(int count) {
     List<Map<String, Object>> inputData = new ArrayList<>();
     for (int i = 0; i < count; ++i) {

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDaoTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDaoTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDaoTest.java
index 5a70636..ec241e4 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDaoTest.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/dao/metaalert/lucene/AbstractLuceneMetaAlertUpdateDaoTest.java
@@ -54,12 +54,10 @@ import org.apache.metron.indexing.dao.RetrieveLatestDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest;
-import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertRetrieveLatestDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus;
 import org.apache.metron.indexing.dao.metaalert.MetaScores;
 import org.apache.metron.indexing.dao.search.GetRequest;
-import org.apache.metron.indexing.dao.search.InvalidSearchException;
 import org.apache.metron.indexing.dao.update.CommentAddRemoveRequest;
 import org.apache.metron.indexing.dao.update.Document;
 import org.apache.metron.indexing.dao.update.PatchRequest;
@@ -157,43 +155,39 @@ public class AbstractLuceneMetaAlertUpdateDaoTest {
     }
 
     @Override
-    public void update(Document update, Optional<String> index) {
+    public Document update(Document update, Optional<String> index) {
+      return null;
     }
 
     @Override
-    public void addCommentToAlert(CommentAddRemoveRequest request) {
+    public Document addCommentToAlert(CommentAddRemoveRequest request) {
+      return null;
     }
 
     @Override
-    public void removeCommentFromAlert(CommentAddRemoveRequest request) {
+    public Document removeCommentFromAlert(CommentAddRemoveRequest request) {
+      return null;
     }
 
     @Override
-    public void addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+    public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) {
+      return null;
     }
 
     @Override
-    public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+    public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) {
+      return null;
     }
 
     @Override
-    public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
+    public Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
         Optional<Long> timestamp) {
-    }
-
-    @Override
-    public MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request) {
       return null;
     }
 
     @Override
-    public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests) {
-      return false;
-    }
-
-    @Override
-    public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status) {
-      return false;
+    public Document createMetaAlert(MetaAlertCreateRequest request) {
+      return null;
     }
   }
 
@@ -762,6 +756,30 @@ public class AbstractLuceneMetaAlertUpdateDaoTest {
     UUID.fromString((String) actualDocument.get(Constants.GUID));
   }
 
+  @Test
+  public void addAlertsToMetaAlertShouldThrowExceptionOnMissingMetaAlert() throws Exception {
+    thrown.expect(IOException.class);
+    thrown.expectMessage("Unable to add alerts to meta alert.  Meta alert with guid some_guid cannot be found.");
+
+    dao.addAlertsToMetaAlert("some_guid", new ArrayList<>());
+  }
+
+  @Test
+  public void removeAlertsFromMetaAlertShouldThrowExceptionOnMissingMetaAlert() throws Exception {
+    thrown.expect(IOException.class);
+    thrown.expectMessage("Unable to remove alerts from meta alert.  Meta alert with guid some_guid cannot be found.");
+
+    dao.removeAlertsFromMetaAlert("some_guid", new ArrayList<>());
+  }
+
+  @Test
+  public void updateMetaAlertStatusShouldThrowExceptionOnMissingMetaAlert() throws Exception {
+    thrown.expect(IOException.class);
+    thrown.expectMessage("Unable to update meta alert status.  Meta alert with guid some_guid cannot be found.");
+
+    dao.updateMetaAlertStatus("some_guid", MetaAlertStatus.INACTIVE);
+  }
+
   // Utility method to manage comparing update maps
   protected boolean updatesMapEquals(Map<Document, Optional<String>> expected,
       Map<Document, Optional<String>> actual) {

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/integration/HBaseDaoIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/integration/HBaseDaoIntegrationTest.java b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/integration/HBaseDaoIntegrationTest.java
index 73a9077..8eaa8f4 100644
--- a/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/integration/HBaseDaoIntegrationTest.java
+++ b/metron-platform/metron-indexing/src/test/java/org/apache/metron/indexing/integration/HBaseDaoIntegrationTest.java
@@ -35,14 +35,13 @@ import org.apache.metron.hbase.mock.MockHTable;
 import org.apache.metron.indexing.dao.AccessConfig;
 import org.apache.metron.indexing.dao.HBaseDao;
 import org.apache.metron.indexing.dao.IndexDao;
-import org.apache.metron.indexing.dao.MultiIndexDao;
 import org.apache.metron.indexing.dao.UpdateIntegrationTest;
 import org.apache.metron.indexing.dao.search.AlertComment;
 import org.apache.metron.indexing.dao.search.GetRequest;
 import org.apache.metron.indexing.dao.update.Document;
 import org.junit.After;
 import org.junit.Assert;
-import org.junit.BeforeClass;
+import org.junit.Before;
 import org.junit.Test;
 
 public class HBaseDaoIntegrationTest extends UpdateIntegrationTest  {
@@ -61,8 +60,8 @@ public class HBaseDaoIntegrationTest extends UpdateIntegrationTest  {
           0x54,0x79,0x70,0x65
   };
 
-  @BeforeClass
-  public static void startHBase() throws Exception {
+  @Before
+  public void startHBase() throws Exception {
     AccessConfig accessConfig = new AccessConfig();
     accessConfig.setMaxSearchResults(1000);
     accessConfig.setMaxSearchGroups(1000);

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrDao.java b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrDao.java
index a840bb4..e6906f3 100644
--- a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrDao.java
+++ b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrDao.java
@@ -124,30 +124,30 @@ public class SolrDao implements IndexDao {
   }
 
   @Override
-  public void update(Document update, Optional<String> index) throws IOException {
-    this.solrUpdateDao.update(update, index);
+  public Document update(Document update, Optional<String> index) throws IOException {
+    return this.solrUpdateDao.update(update, index);
   }
 
   @Override
-  public void batchUpdate(Map<Document, Optional<String>> updates) throws IOException {
-    this.solrUpdateDao.batchUpdate(updates);
+  public Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) throws IOException {
+    return this.solrUpdateDao.batchUpdate(updates);
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
-    this.solrUpdateDao.addCommentToAlert(request);
+  public Document addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
+    return this.solrUpdateDao.addCommentToAlert(request);
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
-    this.solrUpdateDao.removeCommentFromAlert(request);
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
+    return this.solrUpdateDao.removeCommentFromAlert(request);
   }
 
   @Override
-  public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
+  public Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
       Optional<Long> timestamp)
       throws OriginalNotFoundException, IOException {
-    solrUpdateDao.patch(retrieveLatestDao, request, timestamp);
+    return solrUpdateDao.patch(retrieveLatestDao, request, timestamp);
   }
 
   @Override
@@ -156,15 +156,15 @@ public class SolrDao implements IndexDao {
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request, Document latest)
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest)
       throws IOException {
-    this.solrUpdateDao.addCommentToAlert(request, latest);
+    return this.solrUpdateDao.addCommentToAlert(request, latest);
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest)
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest)
       throws IOException {
-    this.solrUpdateDao.removeCommentFromAlert(request, latest);
+    return this.solrUpdateDao.removeCommentFromAlert(request, latest);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertDao.java b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertDao.java
index 4748315..8ef9484 100644
--- a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertDao.java
+++ b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertDao.java
@@ -33,7 +33,6 @@ import org.apache.metron.indexing.dao.RetrieveLatestDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest;
-import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertDao;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus;
 import org.apache.metron.indexing.dao.search.FieldType;
@@ -190,20 +189,20 @@ public class SolrMetaAlertDao implements MetaAlertDao {
   }
 
   @Override
-  public void update(Document update, Optional<String> index) throws IOException {
-    metaAlertUpdateDao.update(update, index);
+  public Document update(Document update, Optional<String> index) throws IOException {
+    return metaAlertUpdateDao.update(update, index);
   }
 
   @Override
-  public void batchUpdate(Map<Document, Optional<String>> updates) {
-    metaAlertUpdateDao.batchUpdate(updates);
+  public Map<Document, Optional<String>> batchUpdate(Map<Document, Optional<String>> updates) {
+    return metaAlertUpdateDao.batchUpdate(updates);
   }
 
   @Override
-  public void patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
+  public Document patch(RetrieveLatestDao retrieveLatestDao, PatchRequest request,
       Optional<Long> timestamp)
       throws OriginalNotFoundException, IOException {
-    metaAlertUpdateDao.patch(retrieveLatestDao, request, timestamp);
+    return metaAlertUpdateDao.patch(retrieveLatestDao, request, timestamp);
   }
 
   @Override
@@ -212,46 +211,46 @@ public class SolrMetaAlertDao implements MetaAlertDao {
   }
 
   @Override
-  public MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request)
+  public Document createMetaAlert(MetaAlertCreateRequest request)
       throws InvalidCreateException, IOException {
     return metaAlertUpdateDao.createMetaAlert(request);
   }
 
   @Override
-  public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
+  public Document addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
       throws IOException {
     return metaAlertUpdateDao.addAlertsToMetaAlert(metaAlertGuid, alertRequests);
   }
 
   @Override
-  public boolean removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
+  public Document removeAlertsFromMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
       throws IOException {
     return metaAlertUpdateDao.removeAlertsFromMetaAlert(metaAlertGuid, alertRequests);
   }
 
   @Override
-  public boolean updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
+  public Document updateMetaAlertStatus(String metaAlertGuid, MetaAlertStatus status)
       throws IOException {
     return metaAlertUpdateDao.updateMetaAlertStatus(metaAlertGuid, status);
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
-    solrDao.addCommentToAlert(request);
+  public Document addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
+    return solrDao.addCommentToAlert(request);
   }
 
-    @Override
-    public void removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
-        solrDao.removeCommentFromAlert(request);
-    }
+  @Override
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
+    return solrDao.removeCommentFromAlert(request);
+  }
 
-    @Override
-    public void addCommentToAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
-        solrDao.addCommentToAlert(request, latest);
-    }
+  @Override
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
+    return solrDao.addCommentToAlert(request, latest);
+  }
 
-    @Override
-    public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
-        solrDao.removeCommentFromAlert(request, latest);
-    }
+  @Override
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest) throws IOException {
+    return solrDao.removeCommentFromAlert(request, latest);
+  }
 }

http://git-wip-us.apache.org/repos/asf/metron/blob/de533063/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertUpdateDao.java
----------------------------------------------------------------------
diff --git a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertUpdateDao.java b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertUpdateDao.java
index 132d872..124d4be 100644
--- a/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertUpdateDao.java
+++ b/metron-platform/metron-solr/src/main/java/org/apache/metron/solr/dao/SolrMetaAlertUpdateDao.java
@@ -28,11 +28,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
-import org.apache.metron.common.Constants;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConfig;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertConstants;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateRequest;
-import org.apache.metron.indexing.dao.metaalert.MetaAlertCreateResponse;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertStatus;
 import org.apache.metron.indexing.dao.metaalert.MetaAlertUpdateDao;
 import org.apache.metron.indexing.dao.metaalert.MetaScores;
@@ -71,7 +69,7 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
   }
 
   @Override
-  public MetaAlertCreateResponse createMetaAlert(MetaAlertCreateRequest request)
+  public Document createMetaAlert(MetaAlertCreateRequest request)
       throws InvalidCreateException, IOException {
     List<GetRequest> alertRequests = request.getAlerts();
     if (request.getAlerts().isEmpty()) {
@@ -120,11 +118,8 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
       // Kick off any updates.
       update(updates);
 
-      MetaAlertCreateResponse createResponse = new MetaAlertCreateResponse();
-      createResponse.setCreated(true);
-      createResponse.setGuid(metaAlert.getGuid());
       solrClient.commit(METAALERTS_COLLECTION);
-      return createResponse;
+      return metaAlert;
     } catch (IOException | SolrServerException e) {
       throw new InvalidCreateException("Unable to create meta alert", e);
     }
@@ -135,10 +130,11 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
    * Updates a document in Solr for a given collection.  Collection is not optional for Solr.
    * @param update The update to be run
    * @param collection The index to be updated. Mandatory for Solr
+   * @return The updated document.
    * @throws IOException Thrown when an error occurs during the write.
    */
   @Override
-  public void update(Document update, Optional<String> collection) throws IOException {
+  public Document update(Document update, Optional<String> collection) throws IOException {
     if (MetaAlertConstants.METAALERT_TYPE.equals(update.getSensorType())) {
       // We've been passed an update to the meta alert.
       throw new UnsupportedOperationException("Meta alerts cannot be directly updated");
@@ -181,28 +177,30 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
     } catch (SolrServerException e) {
       throw new IOException("Unable to update document", e);
     }
+
+    return update;
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
-    getUpdateDao().addCommentToAlert(request);
+  public Document addCommentToAlert(CommentAddRemoveRequest request) throws IOException {
+    return getUpdateDao().addCommentToAlert(request);
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
-    getUpdateDao().removeCommentFromAlert(request);
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request) throws IOException {
+    return getUpdateDao().removeCommentFromAlert(request);
   }
 
   @Override
-  public void addCommentToAlert(CommentAddRemoveRequest request, Document latest)
+  public Document addCommentToAlert(CommentAddRemoveRequest request, Document latest)
       throws IOException {
-    getUpdateDao().addCommentToAlert(request, latest);
+    return getUpdateDao().addCommentToAlert(request, latest);
   }
 
   @Override
-  public void removeCommentFromAlert(CommentAddRemoveRequest request, Document latest)
+  public Document removeCommentFromAlert(CommentAddRemoveRequest request, Document latest)
       throws IOException {
-    getUpdateDao().removeCommentFromAlert(request, latest);
+    return getUpdateDao().removeCommentFromAlert(request, latest);
   }
 
   protected boolean replaceAlertInMetaAlert(Document metaAlert, Document alert) {
@@ -215,9 +213,8 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
   }
 
   @Override
-  public boolean addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
-      throws IOException {
-    boolean success;
+  public Document addAlertsToMetaAlert(String metaAlertGuid, List<GetRequest> alertRequests)
+      throws IOException, IllegalStateException {
     Document metaAlert = getRetrieveLatestDao()
         .getLatest(metaAlertGuid, MetaAlertConstants.METAALERT_TYPE);
     if (MetaAlertStatus.ACTIVE.getStatusString()
@@ -225,7 +222,6 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
       Iterable<Document> alerts = getRetrieveLatestDao().getAllLatest(alertRequests);
       Map<Document, Optional<String>> updates = buildAddAlertToMetaAlertUpdates(metaAlert, alerts);
       update(updates);
-      success = updates.size() != 0;
     } else {
       throw new IllegalStateException("Adding alerts to an INACTIVE meta alert is not allowed");
     }
@@ -234,6 +230,6 @@ public class SolrMetaAlertUpdateDao extends AbstractLuceneMetaAlertUpdateDao imp
     } catch (SolrServerException e) {
       throw new IOException("Unable to commit alerts to metaalert: " + metaAlertGuid, e);
     }
-    return success;
+    return metaAlert;
   }
 }


Mime
View raw message