def testSubmitResultsRecoveryFromMessageQueueNotFound(
      self, messageBusConnectorClassMock):
    # submitResults recovers from the initial MessageQueueNotFound by creating
    # the results message queue and re-publishing the message
    results = [
      ModelCommandResult(commandID="abc", method="testMethod", status=0,
        args={'key1': 4098, 'key2': 4139}),
      ModelInferenceResult(rowID="foo", status=0, anomalyScore=1),
      ModelInferenceResult(rowID="bar", status=0, anomalyScore=2)
    ]

    messageBusConnectorMock = messageBusConnectorClassMock.return_value
    messageBusConnectorMock.publish.side_effect = (
      message_bus_connector.MessageQueueNotFound("from mock test"),
      Mock())

    modelID = "foofar"

    with ModelSwapperInterface() as interface:
      interface.submitResults(modelID=modelID, results=results)

      mqName = interface._resultsQueueName

    # Verify
    messageBusConnectorMock.createMessageQueue.assert_called_once_with(
      mqName, durable=True)

    self.assertEqual(messageBusConnectorMock.publish.call_count, 2)

    msg = ResultMessagePackager.marshal(
      modelID=modelID,
      batchState=BatchPackager.marshal(batch=results))

    messageBusConnectorMock.publish.assert_called_with(mqName, msg,
                                                       persistent=True)
  def testSubmitResultsFailure(self, messageBusConnectorClassMock):
    results = [
      ModelCommandResult(commandID="abc", method="testMethod", status=0,
        args={'key1': 4098, 'key2': 4139}),
      ModelInferenceResult(rowID="foo", status=0, anomalyScore=1),
      ModelInferenceResult(rowID="bar", status=0, anomalyScore=2)
    ]

    messageBusConnectorMock = messageBusConnectorClassMock.return_value
    messageBusConnectorMock.publish.side_effect = (
      message_bus_connector.MessageQueueNotFound("from mock test"),
      Exception("re-publish failed in mock test"))

    modelID = "foofar"

    with self.assertRaises(Exception) as raisesCM:
      with ModelSwapperInterface() as interface:
        mqName = interface._resultsQueueName
        interface.submitResults(modelID=modelID, results=results)

    # Verify
    self.assertEqual(raisesCM.exception.args[0],
                     "re-publish failed in mock test")

    messageBusConnectorMock.createMessageQueue.assert_called_once_with(
      mqName, durable=True)

    self.assertEqual(messageBusConnectorMock.publish.call_count, 2)

    msg = ResultMessagePackager.marshal(
      modelID=modelID,
      batchState=BatchPackager.marshal(batch=results))

    messageBusConnectorMock.publish.assert_called_with(mqName, msg,
                                                       persistent=True)
  def testMarshalAndUnmarshal(self):
    resultBatch = [
      ModelCommandResult(commandID="abc", method="testMethod", status=0,
        args={'key1': 4098, 'key2': 4139}),
      ModelInferenceResult(rowID="foo", status=0, anomalyScore=1),
      ModelInferenceResult(rowID="bar", status=0, anomalyScore=2)
      ]
    batchState = BatchPackager.marshal(batch=resultBatch)
    msg = ResultMessagePackager.marshal(modelID="foobar", batchState=batchState)

    r = ResultMessagePackager.unmarshal(msg)

    self.assertEqual(r.modelID, "foobar")
    self.assertEqual(r.batchState, batchState)


    # Make sure we aren't forgetting to test any returned fields
    self.assertEqual(set(["modelID", "batchState"]), set(r._fields))
  def testContextManagerAndConsumeResults(self, messageBusConnectorClassMock):
    expectedResults = (
      ModelCommandResult(commandID="abc", method="testMethod", status=0,
        args={'key1': 4098, 'key2': 4139}),
      ModelInferenceResult(rowID="foo", status=0, anomalyScore=1.3),
      ModelInferenceResult(rowID="bar", status=0, anomalyScore=2.9)
    )
    modelID = "foobar"
    msg = ResultMessagePackager.marshal(
      modelID=modelID,
      batchState=BatchPackager.marshal(batch=expectedResults))

    messageBusConnectorMock = messageBusConnectorClassMock.return_value

    ackMock = Mock(return_value=None)
    messageBusConnectorMock.consume.return_value = Mock(
      spec_set=message_bus_connector._QueueConsumer,
      __iter__=lambda *args, **kwargs: iter(
        [message_bus_connector._ConsumedMessage(
          body=msg, ack=ackMock)]))

    with ModelSwapperInterface() as interface:
      self.assertEqual(len(interface._consumers), 0)

      consumer = interface.consumeResults()
      self.assertIsNotNone(consumer._mqConsumer)
      self.assertEqual(len(interface._consumers), 1)

      batch = next(iter(consumer))

      self.assertEqual(batch.modelID, modelID)
      self.assertEqual(batch.objects, expectedResults)
      self.assertTrue(callable(batch.ack))
      self.assertIs(batch.ack, ackMock)

      self.assertEqual(set(batch._fields), set(["modelID", "objects", "ack"]))

      consumer.close()
      self.assertIsNone(consumer._mqConsumer)
      self.assertEqual(len(interface._consumers), 0)

    self.assertEqual(len(interface._consumers), 0)
  def testSubmitResults(self, messageBusConnectorClassMock):
    results = [
      ModelCommandResult(commandID="abc", method="testMethod", status=0,
        args={'key1': 4098, 'key2': 4139}),
      ModelInferenceResult(rowID="foo", status=0, anomalyScore=1),
      ModelInferenceResult(rowID="bar", status=0, anomalyScore=2)
    ]

    messageBusConnectorMock = messageBusConnectorClassMock.return_value

    interface = ModelSwapperInterface()

    modelID = "foofar"
    msg = ResultMessagePackager.marshal(
      modelID=modelID,
      batchState=BatchPackager.marshal(batch=results))

    interface.submitResults(modelID=modelID, results=results)

    mqName = interface._resultsQueueName

    messageBusConnectorMock.publish.assert_called_once_with(mqName, msg,
                                                            persistent=True)