def testPublishMetricDataWithDuplicateKeys(self, connectDynamoDB,
                                             _gracefulCreateTable):
    """ Test for elimination of rows with duplicate keys by _publishMetricData
    """
    metricId = "3b035a5916994f2bb950f5717138f94b"

    rowTemplate = dict(
      rowid=99,
      ts=epochFromNaiveUTCDatetime(datetime(2015, 3, 20, 0, 46, 28)),
      value=10305.0,
      rawAnomaly=0.275,
      anomaly=0.999840891
    )

    row1 = dict(rowTemplate)
    row2 = dict(rowTemplate)
    row2["rowid"] = row1["rowid"] + 1
    rows = [row1, row2]

    service = DynamoDBService()

    service._publishMetricData(metricId, rows)

    data = dynamodb_service.convertInferenceResultRowToMetricDataItem(metricId,
                                                                      row1)
    mockPutItem = (service._metric_data.batch_write.return_value.__enter__
                   .return_value.put_item)
    mockPutItem.assert_called_once_with(data=data._asdict(), overwrite=True)
  def testMessageHandlerRoutesMetricDataToDynamoDB(
      self, _amqpUtilsMock,
      deserializeModelResult, connectDynamoDB, _gracefulCreateTable):
    """ Given a batch of model inference results, send the appropriate data to
    DynamoDB tables according to design in an environment where both rabbitmq
    and dynamodb are mocked out
    """

    # We're going to mostly mock out all of the arguments to
    # DynamoDBService.messageHandler() since it is normally called by amqp lib.
    # Then simulate the process of handling an inbound batch of model inference
    # results and assert that the appropriate put_item() calls are made at the
    # other end.
    message = amqp.messages.ConsumerMessage(
      body=Mock(),
      properties=Mock(headers=dict()),
      methodInfo=amqp.messages.MessageDeliveryInfo(consumerTag=Mock(),
                                                   deliveryTag=Mock(),
                                                   redelivered=False,
                                                   exchange=Mock(),
                                                   routingKey=""),
      ackImpl=Mock(),
      nackImpl=Mock())

    # We will have to bypass the normal serialize/deserialize phases to avoid
    # dependency on sqlalchemy rowproxy.  Instead, we'll just mock out the
    # AnomalyService.deserializeModelResult() call, returning an object that
    # approximates a batch of model inference results as much as possible

    now = int(time.time())

    resultRow = dict(
      rowid=4790,
      ts=now,
      value=9305.0,
      rawAnomaly=0.775,
      anomaly=0.999840891
    )

    metricId = "3b035a5916994f2bb950f5717138f94b"

    deserializeModelResult.return_value = dict(
      metric=dict(
        uid=metricId,
        name="XIGNITE.AGN.VOLUME",
        description="XIGNITE.AGN.VOLUME",
        resource="Resource-of-XIGNITE.AGN.VOLUME",
        location = "",
        datasource = "custom",
        spec=dict(
          userInfo=dict(
            symbol="AGN",
            metricType="StockVolume",
            metricTypeName="Stock Volume"
          )
        )
      ),

      results=[resultRow]
    )

    service = DynamoDBService()
    service.messageHandler(message)

    deserializeModelResult.assert_called_once_with(message.body)

    mockMetricDataPutItem = (
      service._metric_data.batch_write.return_value.__enter__
      .return_value.put_item)
    data = dynamodb_service.convertInferenceResultRowToMetricDataItem(
      metricId, resultRow)
    mockMetricDataPutItem.assert_called_once_with(data=data._asdict(),
                                                  overwrite=True)

    self.assertFalse(service._metric_tweets.batch_write.called)


    # Make sure that a model command result doesn't get mistaken for an
    # inference result batch
    deserializeModelResult.return_value = Mock()
    message.properties = Mock(headers=dict(dataType="model-cmd-result"))
    message.body = Mock()
    service = DynamoDBService()
    with patch.object(service, "_handleModelCommandResult",
                      spec_set=service._handleModelCommandResult):
      service.messageHandler(message)
      service._handleModelCommandResult.assert_called_once_with(message.body)