def testLoadMetricSpecs(self, urllib2, metricDataBatchWriter):
    metricSpecs = xignite_stock_agent.loadMetricSpecs()

    for spec in metricSpecs:
      self.assertIsInstance(spec, xignite_stock_agent.StockMetricSpec)

    self.assertEqual(len(metricSpecs), len(set(metricSpecs)))
  def testMain(self, time, Pool, urllib2, metricDataBatchWriter):
    # Load metric specs from metric configuration
    symbolToMetricSpecs = defaultdict(list)
    for spec in xignite_stock_agent.loadMetricSpecs():
      symbolToMetricSpecs[spec.symbol].append(spec)

    symbolIter = symbolToMetricSpecs.itervalues()

    time.sleep.side_effect = [None, None, KeyboardInterrupt()]
    Pool.return_value.imap_unordered.return_value = iter([
      ({"Symbol": next(symbolIter)[0].symbol}, [Mock()]),
      ({"Symbol": next(symbolIter)[0].symbol}, [Mock()]),
      ({"Symbol": next(symbolIter)[0].symbol}, [Mock()])
    ])
    with patch.object(sys, "argv", [None, "--apitoken=foobar"]):
      xignite_stock_agent.main()

    self.assertTrue(Pool.called)
    self.assertEqual(Pool.return_value.imap_unordered.call_count, 3)
    self.assertEqual(Pool.return_value.apply_async.call_count, 6)