text: """
  This file demonstrates writing tests using the unittest module. These will pass
  when you run "manage.py test".
  
  Replace this with more appropriate tests for your application.
  """
  from __future__ import unicode_literals
  from datetime import datetime, timedelta
  try:
      from unittest.mock import call, patch, Mock
  except ImportError:
      from mock import call, patch, Mock
  
  from django.test import TestCase
  from django.test.utils import override_settings
  
  from ..models import R, dedupe
  
  
  TEST_SETTINGS = {
      'HOST': 'localhost',
      'PORT': 6379,
      'DB': 0,
      'PASSWORD': None,
      'SOCKET_TIMEOUT': None,
      'SOCKET_CONNECTION_POOL': None,
      'MIN_GRANULARITY': 'seconds',
      'MAX_GRANULARITY': 'yearly',
      'MONDAY_FIRST_DAY_OF_WEEK': False,
      'USE_ISO_WEEK_NUMBER': False,
  }
  
  
  @override_settings(REDIS_METRICS=TEST_SETTINGS)
  class TestR(TestCase):
      """Tests for the ``R`` class."""
  
      def setUp(self):
          # Patch the connection to redis, but keep a reference to the
          # created StrictRedis instance, so we can make assertions about how
          # it's called.
          self.redis_patcher = patch('redis_metrics.models.redis.StrictRedis')
          mock_StrictRedis = self.redis_patcher.start()
          self.redis = mock_StrictRedis.return_value
          self.r = R()
  
      def tearDown(self):
          self.redis = self.redis_patcher.stop()
          super(TestR, self).tearDown()
  
      def test_dedupe(self):
          """Test the redis_metrics.models.dedupe function."""
          self.assertEqual(
              list(dedupe(['a', 'a', 'b', 'c', 'b', 'c', 'c', 'c'])),
              ['a', 'b', 'c']
          )
  
      def test__init__(self):
          """Test creation of an R object with parameters."""
          with patch('redis_metrics.models.redis.StrictRedis') as mock_redis:
              kwargs = {
                  'decode_responses': True,
                  'categories_key': 'CAT',
                  'metric_slugs_key': 'MSK',
                  'gauge_slugs_key': 'GSK',
                  'host': 'HOST',
                  'port': 'PORT',
                  'db': 'DB',
                  'password': 'PASSWORD',
                  'socket_timeout': 1,
                  'connection_pool': 1
              }
              inst = R(**kwargs)
              self.assertEqual(inst.host, "HOST")
              self.assertEqual(inst.port, "PORT")
              self.assertEqual(inst.db, "DB")
              self.assertEqual(inst.password, 'PASSWORD')
              self.assertEqual(inst.socket_timeout, 1)
              self.assertEqual(inst.connection_pool, 1)
              self.assertEqual(inst._categories_key, "CAT")
              self.assertEqual(inst._metric_slugs_key, "MSK")
              self.assertEqual(inst._gauge_slugs_key, "GSK")
              mock_redis.assert_called_once_with(
                  decode_responses=True,
                  host='HOST',
                  port='PORT',
                  db='DB',
                  password="PASSWORD",
                  socket_timeout=1,
                  connection_pool=1
              )
  
      def test__init__with_default_kwargs(self):
          """Test creation of an R object without parameters."""
          r_kwargs = {
              'decode_responses': True,
              'host': 'localhost',
              'db': 0,
              'port': 6379,
              'password': None,
              'connection_pool': None,
              'socket_timeout': None
          }
          with patch('redis_metrics.models.redis.StrictRedis') as mock_redis:
              inst = R()
              self.assertEqual(inst.host, 'localhost')
              self.assertEqual(inst.port, 6379)
              self.assertEqual(inst.db, 0)
              self.assertEqual(inst.password, None)
              self.assertEqual(inst.socket_timeout, None)
              self.assertEqual(inst.connection_pool, None)
              self.assertEqual(inst._categories_key, 'categories')
              self.assertEqual(inst._metric_slugs_key, "metric-slugs")
              self.assertEqual(inst._gauge_slugs_key, "gauge-slugs")
              mock_redis.assert_called_once_with(**r_kwargs)
  
      def test__date_range(self):
          """Tests ``R._date_range`` at various granularities *without* a
          ``since`` date."""
          # minutes, seconds and hours should be capped at 300, 480, and 720
          d = datetime(2014, 1, 1)
          self.assertEqual(len(list(self.r._date_range('seconds', d))), 300)
          self.assertEqual(len(list(self.r._date_range('minutes', d))), 480)
          self.assertEqual(len(list(self.r._date_range('hourly', d))), 720)
  
          # Everything else should have a timedelta of 7 days
          self.assertEqual(len(list(self.r._date_range('daily', None))), 8)
          self.assertEqual(len(list(self.r._date_range('weekly', None))), 8)
          self.assertEqual(len(list(self.r._date_range('monthly', None))), 8)
          self.assertEqual(len(list(self.r._date_range('yearly', None))), 8)
  
          # Test with a specified `to` argument.
          since = datetime(2014, 1, 1)
          to = datetime(2015, 1, 1)
          self.assertEqual(len(list(self.r._date_range('daily', since, to))), 366)
          self.assertEqual(len(list(self.r._date_range('weekly', since, to))), 366)
          self.assertEqual(len(list(self.r._date_range('monthly', since, to))), 366)
          self.assertEqual(len(list(self.r._date_range('yearly', since, to))), 366)
  
      def test__date_range_seconds(self):
          """Tests ``R._date_range`` at the "seconds" granularity."""
          since = datetime.utcnow() - timedelta(seconds=5)
          values = self.r._date_range('seconds', since)
          self.assertEqual(len(list(values)), 5)
  
      def test__date_range_minutes(self):
          """Tests ``R._date_range`` at the "minutes" granularity."""
          since = datetime.utcnow() - timedelta(minutes=5)
          values = self.r._date_range('minutes', since)
          self.assertEqual(len(list(values)), 5)
  
      def test__date_range_hourly(self):
          """Tests ``R._date_range`` at the "hourly" granularity."""
          since = datetime.utcnow() - timedelta(hours=5)
          values = self.r._date_range('hourly', since)
          self.assertEqual(len(list(values)), 5)
  
      def test__date_range_daily(self):
          """Tests ``R._date_range`` at the "daily" granularity."""
          since = datetime.utcnow() - timedelta(days=5)
          values = self.r._date_range('daily', since)
          self.assertEqual(len(list(values)), 6)  # 6 because we do days + 1
  
      def test__date_range_weekly(self):
          """Tests ``R._date_range`` at the "weekly" granularity."""
          since = datetime.utcnow() - timedelta(days=5)
          values = self.r._date_range('weekly', since)
          self.assertEqual(len(list(values)), 6)  # 6 because we do days + 1
  
      def test__date_range_monthly(self):
          """Tests ``R._date_range`` at the "monthly" granularity."""
          since = datetime.utcnow() - timedelta(days=5)
          values = self.r._date_range('montly', since)
          self.assertEqual(len(list(values)), 6)  # 6 because we do days + 1
  
      def test__date_range_yearly(self):
          """Tests ``R._date_range`` at the "yearly" granularity."""
          since = datetime.utcnow() - timedelta(days=5)
          values = self.r._date_range('yearly', since)
          self.assertEqual(len(list(values)), 6)  # 6 because we do days + 1
  
      def test_categories(self):
          """Verify that ``R.categories()`` calls redis SMEMBERS command."""
          self.r.categories()
          self.redis.smembers.assert_called_once_with("categories")
  
      def test__category_key(self):
          """Creates a redis key for a given category string."""
          self.assertEqual(
              self.r._category_key("Sample Category"),
              u"c:Sample Category"
          )
  
      def test__category_slugs(self):
          """Verify that this returns an empty list or a list of slugs."""
          # When there are no results from redis
          with patch('redis_metrics.models.redis.StrictRedis') as mock_redis:
              mock_redis.return_value.smembers.return_value = set([])
              r = R()
              result = r._category_slugs("Sample Category")
              self.assertEqual(len(result), 0)
  
          # When there are no results from redis
          with patch('redis_metrics.models.redis.StrictRedis') as mock_redis:
              mock_redis.return_value.smembers.return_value = set(["slug-a", "slug-b"])
              r = R()
              result = r._category_slugs("Sample Category")
              self.assertEqual(set(result), set(['slug-a', 'slug-b']))
  
      @patch.object(R, '_category_slugs')
      def test__categorize(self, mock_category_slugs):
          """Categorizing a slug should add the correct key/values to Redis,
          and it should store the Category in a redis set."""
  
          # Sample category and metric slug
          cat = "Sample Category"
          cat_key = "c:Sample Category"
          slug = "sample-slug"
  
          with patch('redis_metrics.models.redis.StrictRedis') as mock_redis:
              redis_instance = mock_redis.return_value
              r = R()
  
              r._categorize(slug, cat)
              calls = [call.sadd(cat_key, slug), call.sadd("categories", cat)]
              redis_instance.assert_has_calls(calls, any_order=True)
  
      def test__granularities(self):
          """Tests ``R._granularities with default test settings."""
          # With default settings, min/max granularity is "seconds" and "yearly"
          self.assertEqual(
              list(self.r._granularities()),
              ['seconds', 'minutes', 'hourly', 'daily', 'weekly', 'monthly', 'yearly']
          )
  
      def test__granularities_with_altered_min(self):
          """Tests ``R._granularities with an altered minimum value."""
          test_settings = TEST_SETTINGS.copy()
          test_settings['MIN_GRANULARITY'] = 'daily'
          with override_settings(REDIS_METRICS=test_settings):
              self.assertEqual(
                  list(self.r._granularities()),
                  ['daily', 'weekly', 'monthly', 'yearly']
              )
  
      def test__granularities_with_altered_max(self):
          """Tests ``R._granularities with an altered maximum value."""
          test_settings = TEST_SETTINGS.copy()
          test_settings['MAX_GRANULARITY'] = 'daily'
          with override_settings(REDIS_METRICS=test_settings):
              self.assertEqual(
                  list(self.r._granularities()),
                  ['seconds', 'minutes', 'hourly', 'daily']
              )
  
      def test_get_metric_key_pattern_seconds(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('seconds', slug, date),
              "m:test-slug:s:2019-01-02-03-04-05"
          )
  
      def test_get_metric_key_pattern_minutes(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('minutes', slug, date),
              "m:test-slug:i:2019-01-02-03-04"
          )
  
      def test_get_metric_key_pattern_hourly(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('hourly', slug, date),
              "m:test-slug:h:2019-01-02-03"
          )
  
      def test_get_metric_key_pattern_daily(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('daily', slug, date),
              "m:test-slug:2019-01-02"
          )
  
      def test_get_metric_key_pattern_weekly_sunday_as_first(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['MONDAY_FIRST_DAY_OF_WEEK'] = False
          with override_settings(REDIS_METRICS=test_settings):
              slug = "test-slug"
              date = datetime(2012, 4, 1, 3, 4, 5)
              self.assertEqual(
                  self.r._get_metric_key_pattern('weekly', slug, date),
                  "m:test-slug:w:2012-14"
              )
  
      def test_get_metric_key_pattern_weekly_monday_at_first(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['MONDAY_FIRST_DAY_OF_WEEK'] = True
          with override_settings(REDIS_METRICS=test_settings):
              slug = "test-slug"
              date = datetime(2012, 4, 1, 3, 4, 5)
              self.assertEqual(
                  self.r._get_metric_key_pattern('weekly', slug, date),
                  "m:test-slug:w:2012-13"
              )
  
      def test_get_metric_key_pattern_weekly_iso_week(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['USE_ISO_WEEK_NUMBER'] = True
          with override_settings(REDIS_METRICS=test_settings):
              slug = "test-slug"
              date = datetime(2019, 1, 2, 3, 4, 5)
              self.assertEqual(
                  self.r._get_metric_key_pattern('weekly', slug, date),
                  "m:test-slug:w:2019-1"
              )
  
      def test_get_metric_key_pattern_monthly(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('monthly', slug, date),
              "m:test-slug:m:2019-01"
          )
  
      def test_get_metric_key_pattern_yearly(self):
          slug = "test-slug"
          date = datetime(2019, 1, 2, 3, 4, 5)
          self.assertEqual(
              self.r._get_metric_key_pattern('yearly', slug, date),
              "m:test-slug:y:2019"
          )
  
      def test__build_keys(self):
          """Tests ``R._build_keys``. with default arguments."""
          with patch('redis_metrics.models.datetime') as mock_datetime:
              mock_datetime.utcnow.return_value = datetime(2014, 7, 2, 12, 6, 34)
              expected_results = [
                  "m:test-slug:s:2014-07-02-12-06-34",
                  "m:test-slug:i:2014-07-02-12-06",
                  "m:test-slug:h:2014-07-02-12",
                  "m:test-slug:2014-07-02",
                  "m:test-slug:w:2014-26",
                  "m:test-slug:m:2014-07",
                  "m:test-slug:y:2014",
              ]
              keys = self.r._build_keys('test-slug')
              self.assertEqual(keys, expected_results)
  
      def test__build_keys_seconds(self):
          """Tests ``R._build_keys``. with a *seconds* granularity."""
          d = datetime(2012, 4, 1, 11, 30, 59)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='seconds')
          self.assertEqual(keys, ['m:test-slug:s:2012-04-01-11-30-59'])
  
      def test__build_keys_minutes(self):
          """Tests ``R._build_keys``. with a *minutes* granularity."""
          d = datetime(2012, 4, 1, 11, 30)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='minutes')
          self.assertEqual(keys, ['m:test-slug:i:2012-04-01-11-30'])
  
      def test__build_keys_hourly(self):
          """Tests ``R._build_keys``. with a *hourly* granularity."""
          d = datetime(2012, 4, 1, 11, 30)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='hourly')
          self.assertEqual(keys, ['m:test-slug:h:2012-04-01-11'])
  
      def test__build_keys_daily(self):
          """Tests ``R._build_keys``. with a *daily* granularity."""
          d = datetime(2012, 4, 1)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='daily')
          self.assertEqual(keys, ['m:test-slug:2012-04-01'])
  
      def test__build_keys_weekly(self):
          """Tests ``R._build_keys``. with a *weekly* granularity."""
          d = datetime(2012, 4, 1)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='weekly')
          self.assertEqual(keys, ['m:test-slug:w:2012-14'])
  
      def test__build_keys_weekly_week_starts_monday(self):
          """Tests ``R._build_keys``. with a *weekly* granularity."""
          test_settings = TEST_SETTINGS.copy()
          test_settings['MONDAY_FIRST_DAY_OF_WEEK'] = True
          with override_settings(REDIS_METRICS=test_settings):
              d = datetime(2012, 4, 1)  # April Fools!
              keys = self.r._build_keys('test-slug', date=d, granularity='weekly')
              self.assertEqual(keys, ['m:test-slug:w:2012-13'])
  
      def test__build_keys_weekly_iso_week(self):
          """Tests ``R._build_keys``. with a *weekly* granularity."""
          test_settings = TEST_SETTINGS.copy()
          test_settings['USE_ISO_WEEK_NUMBER'] = True
          with override_settings(REDIS_METRICS=test_settings):
              d1 = datetime(2018, 12, 30)
              keys = self.r._build_keys('test-slug', date=d1, granularity='weekly')
              self.assertEqual(keys, ['m:test-slug:w:2018-52'])
              d2 = datetime(2018, 12, 31)
              keys = self.r._build_keys('test-slug', date=d2, granularity='weekly')
              self.assertEqual(keys, ['m:test-slug:w:2019-1'])
              d3 = datetime(2019, 1, 1)
              keys = self.r._build_keys('test-slug', date=d3, granularity='weekly')
              self.assertEqual(keys, ['m:test-slug:w:2019-1'])
  
      def test__build_keys_monthly(self):
          """Tests ``R._build_keys``. with a *monthly* granularity."""
          d = datetime(2012, 4, 1)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='monthly')
          self.assertEqual(keys, ['m:test-slug:m:2012-04'])
  
      def test__build_keys_yearly(self):
          """Tests ``R._build_keys``. with a *yearly* granularity."""
          d = datetime(2012, 4, 1)  # April Fools!
          keys = self.r._build_keys('test-slug', date=d, granularity='yearly')
          self.assertEqual(keys, ['m:test-slug:y:2012'])
  
      def test_metric_slugs(self):
          """Test that ``R.metric_slugs`` makes a call to Redis SMEMBERS."""
          self.r.metric_slugs()
          self.redis.assert_has_calls([call.smembers(self.r._metric_slugs_key)])
  
      @patch.object(R, '_category_slugs')
      def test_metric_slugs_by_category(self, mock_category_slugs):
          """Test that we get metric slugs organized by category."""
          # set up a mock return value for the category's redis set
          self.redis.smembers.return_value = ['Sample Category']
          # set up return value for mock call to _category_slugs
          mock_category_slugs.return_value = ['foo', 'bar']
  
          # Since this method all calls out to ``R.metric_slugs``, let's patch
          # that so it returns a list of all slugs, one of which will not be
          # categorized
          self.r.metric_slugs = Mock(return_value=['foo', 'bar', 'baz'])
  
          # Now, test the thing.
          result = self.r.metric_slugs_by_category()
          expected_result = {
              'Sample Category': ['foo', 'bar'],
              'Uncategorized': ['baz']
          }
          self.assertEqual(result, expected_result)
          self.redis.smembers.assert_called_once_with("categories")
          mock_category_slugs.assert_called_once_with("Sample Category")
          self.r.metric_slugs.assert_called_once_with()
  
      def test_delete_metric(self):
          """Verify that ``R.delete_metric`` deletes all keys and removes keys
          from the set of metric slugs."""
  
          # Make sure KEYS returns some data
          self.redis.keys.return_value = ["m:slug:0", "m:slug:1"]
          self.r.delete_metric('slug')  # call delete_metric
  
          # Verify that the metric data is removed as are the keys from the set
          self.redis.assert_has_calls([
              call.keys("m:slug:*"),
              call.delete("m:slug:0", "m:slug:1"),
              call.srem(self.r._metric_slugs_key, "slug")
          ])
  
      @patch.object(R, '_build_keys')
      def test_set_metric(self, mock_build_keys):
          """Test setting metrics using ``R.set_metric``."""
          # Define redis keys
          mock_build_keys.return_value = [
              'm:test-slug:s:2000-01-02-11-45-30',
              'm:test-slug:i:2000-01-02-11-45',
              'm:test-slug:h:2000-01-02-11',
              'm:test-slug:2000-01-02',
              'm:test-slug:m:2000-01',
              'm:test-slug:w:2000-01',
              'm:test-slug:y:2000'
          ]
          slug = 'test-slug'
          value = 42
  
          # get the metric keys so we can check for the appropriate calls
          self.r.set_metric(slug, value)
  
          # Verify that setting a metric adds the appropriate slugs to the keys
          # set and then incrememts each key
          self.redis.sadd.assert_called_once_with('metric-slugs', slug)
          self.redis.mset.assert_called_once_with({
              'm:test-slug:s:2000-01-02-11-45-30': 42,
              'm:test-slug:i:2000-01-02-11-45': 42,
              'm:test-slug:h:2000-01-02-11': 42,
              'm:test-slug:2000-01-02': 42,
              'm:test-slug:m:2000-01': 42,
              'm:test-slug:w:2000-01': 42,
              'm:test-slug:y:2000': 42,
          })
  
          # Expiration should not have gotten called
          self.assertFalse(self.redis.expire.called)
  
      @patch.object(R, '_build_keys')
      def test_set_metric_with_expiration(self, mock_build_keys):
          """Test setting metrics using ``R.set_metric`` with an expiration."""
          # Define redis keys
          mock_build_keys.return_value = [
              'm:test-slug:s:2000-01-02-11-45-30',
              'm:test-slug:i:2000-01-02-11-45',
              'm:test-slug:h:2000-01-02-11',
              'm:test-slug:2000-01-02',
              'm:test-slug:m:2000-01',
              'm:test-slug:w:2000-01',
              'm:test-slug:y:2000'
          ]
          slug = 'test-slug'
          value = 42
  
          # get the metric keys so we can check for the appropriate calls
          self.r.set_metric(slug, value, expire=500)
  
          # Verify that each key had an expiration set.
          self.redis.expire.assert_has_calls([
              call('m:test-slug:s:2000-01-02-11-45-30', 500),
              call('m:test-slug:i:2000-01-02-11-45', 500),
              call('m:test-slug:h:2000-01-02-11', 500),
              call('m:test-slug:2000-01-02', 500),
              call('m:test-slug:m:2000-01', 500),
              call('m:test-slug:w:2000-01', 500),
              call('m:test-slug:y:2000', 500),
          ])
  
      @patch.object(R, '_categorize')
      def test_set_metric_with_category(self, mock_categorize):
          """Test setting metrics using ``R.set_metric`` when a category
          is provided."""
  
          # get the metric keys so we can check for the appropriate calls
          self.r.set_metric('test-slug', 42, category='Test Category')
          mock_categorize.assert_called_once_with('test-slug', "Test Category")
  
      def test_metric(self):
          """Test setting metrics using ``R.metric``."""
  
          slug = 'test-metric'
          n = 1
  
          # get the keys used for the metric, so we can check for the appropriate
          # calls
          keys = self.r._build_keys(slug)
          second, minute, hour, day, week, month, year = keys
          self.r.metric(slug, num=n)
  
          # Verify that setting a metric adds the appropriate slugs to the keys
          # set and then incrememts each key
          self.redis.assert_has_calls([
              call.sadd(self.r._metric_slugs_key, slug),
              call.pipeline(),
              call.pipeline().incr(second, n),
              call.pipeline().incr(minute, n),
              call.pipeline().incr(hour, n),
              call.pipeline().incr(day, n),
              call.pipeline().incr(week, n),
              call.pipeline().incr(month, n),
              call.pipeline().incr(year, n),
          ])
  
          # Expiration should not have gotten called
          self.assertFalse(self.redis.expire.called)
  
      def test_metric_with_overridden_granularities(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['MIN_GRANULARITY'] = 'daily'
          test_settings['MAX_GRANULARITY'] = 'weekly'
          with override_settings(REDIS_METRICS=test_settings):
              slug = 'test-metric'
              n = 1
  
              # get the keys used for the metric, so we can check for the appropriate
              # calls
              daily, weekly = self.r._build_keys(slug)
              self.r.metric(slug, num=n)
  
              # Verify that setting a metric adds the appropriate slugs to the keys
              # set and then incrememts each key
              self.redis.assert_has_calls([
                  call.sadd(self.r._metric_slugs_key, slug),
                  call.pipeline(),
                  call.pipeline().incr(daily, n),
                  call.pipeline().incr(weekly, n),
              ])
  
              # Expiration should not have gotten called
              self.assertFalse(self.redis.expire.called)
  
      @patch.object(R, '_categorize')
      def test_metric_with_category(self, mock_categorize):
          """The ``metric`` method should call ``_categorize`` if passed a
          ``category`` argument."""
          category = "Some Category"
          slug = 'categorized-metric'
          n = 1
  
          # get the keys used for the metric, so we can check for calls
          keys = self.r._build_keys(slug)
          second, minute, hour, day, week, month, year = keys
          self.r.metric(slug, num=n, category=category)
  
          # Verify that setting a metric adds the appropriate slugs to the keys
          # set and then incrememts each key
          self.redis.assert_has_calls([
              call.sadd(self.r._metric_slugs_key, slug),
              call.pipeline(),
              call.pipeline().incr(second, n),
              call.pipeline().incr(minute, n),
              call.pipeline().incr(hour, n),
              call.pipeline().incr(day, n),
              call.pipeline().incr(week, n),
              call.pipeline().incr(month, n),
              call.pipeline().incr(year, n),
          ])
  
          # Make sure this gets categorized.
          mock_categorize.assert_called_once_with(slug, category)
  
          # Expiration should not have gotten called
          self.assertFalse(self.redis.expire.called)
  
      @patch.object(R, '_categorize')
      def test_metric_with_expiration(self, mock_categorize):
          """The ``metric`` method should call the redis ``expire`` method if
          passed an ``expire`` argument."""
  
          slug = 'categorized-metric'
          n = 1
  
          # get the keys used for the metric, so we can check for calls
          keys = self.r._build_keys(slug)
          self.r.metric(slug, num=n, expire=3600)
  
          # Verify that setting a metric adds the appropriate slugs to the keys
          # set and then incrememts each key
          call_list = [call.sadd(self.r._metric_slugs_key, slug), call.pipeline()]
          for k in keys:
              call_list.append(call.pipeline().incr(k, n))
              call_list.append(call.pipeline().expire(k, 3600))
  
          self.redis.assert_has_calls(call_list)
  
          # Make sure nothing was categorized.
          self.assertFalse(mock_categorize.called)
  
      def test_get_metric(self):
          """Tests getting a single metric; ``R.get_metric``."""
          slug = 'test-metric'
          self.r.get_metric(slug)
  
          # Verify that we GET the keys from redis
          sec, min, hour, day, week, month, year = self.r._build_keys(slug)
          self.redis.assert_has_calls([
              call.get(sec),
              call.get(min),
              call.get(hour),
              call.get(day),
              call.get(week),
              call.get(month),
              call.get(year),
          ])
  
      def test_get_metric_with_overridden_granularities(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['MIN_GRANULARITY'] = 'daily'
          test_settings['MAX_GRANULARITY'] = 'weekly'
          with override_settings(REDIS_METRICS=test_settings):
              slug = 'test-metric'
              self.r.get_metric(slug)
  
              # Verify that we GET the keys from redis
              day, week = self.r._build_keys(slug)
              self.redis.assert_has_calls([
                  call.get(day),
                  call.get(week),
              ])
  
      def test_get_metrics(self):
          # Set a return value for mget, so all of the method gets exercised.
          prev_return = self.redis.mget.return_value
          self.redis.mget.return_value = ['1', '2']
  
          # Slugs for metrics we want
          slugs = ['metric-1', 'metric-2']
  
          # Build the various keys for each metric
          keys_list = []
          for s in slugs:
              keys_list.append(self.r._build_keys(s))
  
          # construct the calls to redis.mget
          calls = [call(*keys) for keys in keys_list]
  
          # Test our method
          self.r.get_metrics(slugs)
          self.assertEqual(self.redis.mget.call_args_list, calls)
          self.assertTrue(self.redis.mget.called)  # mget was called...
          self.assertEqual(self.redis.mget.call_count, 2)  # ...twice
  
          # Reset mget's previous return value
          self.redis.mget.return_value = prev_return
  
      def test_get_metrics_with_overridden_granularities(self):
          test_settings = TEST_SETTINGS.copy()
          test_settings['MIN_GRANULARITY'] = 'daily'
          test_settings['MAX_GRANULARITY'] = 'weekly'
          with override_settings(REDIS_METRICS=test_settings):
              # Set a return value for mget, so all of the method gets exercised.
              prev_return = self.redis.mget.return_value
              self.redis.mget.return_value = ['1', '2']
  
              # Slugs for metrics we want
              slugs = ['metric-1', 'metric-2']
  
              # Build the various keys for each metric
              keys_list = []
              for s in slugs:
                  keys_list.append(self.r._build_keys(s))
  
              # construct the calls to redis.mget
              calls = [call(*keys) for keys in keys_list]
  
              # Test our method
              self.r.get_metrics(slugs)
              self.assertEqual(self.redis.mget.call_args_list, calls)
              self.assertTrue(self.redis.mget.called)  # mget was called...
              self.assertEqual(self.redis.mget.call_count, 2)  # ...twice
  
              # Reset mget's previous return value
              self.redis.mget.return_value = prev_return
  
      def test_get_category_metrics(self):
          """returns metrics for a given category"""
          r = R()
          # Mock methods called by `get_category_metrics`
          r._category_slugs = Mock(return_value=['some-slug'])
          r.get_metrics = Mock(return_value="RESULT")
          results = r.get_category_metrics("Sample Category")
          self.assertEqual(results, 'RESULT')
          r._category_slugs.assert_called_once_with("Sample Category")
          r.get_metrics.assert_called_once_with(['some-slug'])
  
      def test_delete_category(self):
          r_kwargs = {
              'decode_responses': True,
              'host': 'localhost',
              'db': 0,
              'port': 6379,
              'password': None,
              'connection_pool': None,
              'socket_timeout': None
          }
          with patch("redis_metrics.models.redis.StrictRedis") as mock_redis:
              r = R()
              r.delete_category("Foo")
              mock_redis.assert_has_calls([
                  call(**r_kwargs),
                  call().delete('c:Foo'),
                  call().srem("categories", "Foo")
              ])
  
      @patch.object(R, "delete_category")
      def test_reset_category_with_no_metrics(self, mock_delete_category):
          """Calling ``reset_category`` with an empty list of metrics should
          just delete the category."""
          with patch("redis_metrics.models.redis.StrictRedis"):
              r = R()
              r.reset_category("Stuff", [])
              mock_delete_category.assert_called_once_with("Stuff")
  
      def test_reset_category(self):
          r_kwargs = {
              'decode_responses': True,
              'host': 'localhost',
              'db': 0,
              'port': 6379,
              'password': None,
              'connection_pool': None,
              'socket_timeout': None
          }
          with patch("redis_metrics.models.redis.StrictRedis") as mock_redis:
              r = R()
              r.reset_category("Stuff", ['foo', 'bar'])
              mock_redis.assert_has_calls([
                  call(**r_kwargs),
                  call().sadd('c:Stuff', 'foo', 'bar'),
                  call().sadd('categories', 'Stuff'),
              ])
  
      def _metric_history_keys(self, slugs, since=None, to=None,
                               granularity='daily'):
          """generates the same list of keys used in ``get_metric_history``.
          These can then be used to test for calls to redis. Note: This is
          duplicate code from ``get_metric_history`` :-/ """
          if type(slugs) != list:
              slugs = [slugs]
          keys = []
          for slug in slugs:
              for date in self.r._date_range(granularity, since, to):
                  keys += self.r._build_keys(slug, date, granularity)
          keys = list(dedupe(keys))
          return keys
  
      def _test_get_metric_history(self, slugs, since=None, to=None,
                                   granularity=None):
          """actual test code for ``R.get_metric_history``."""
          keys = self._metric_history_keys(slugs, since, to, granularity)
          self.r.get_metric_history(
              slugs, since=since, to=to, granularity=granularity)
          self.redis.assert_has_calls([call.mget(keys)])
  
      def test_get_metric_history_hourly(self):
          """Tests ``R.get_metric_history`` with hourly granularity."""
          self._test_get_metric_history('test-slug', granularity='hourly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              'test-slug',
              since=datetime(2014, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='hourly'
          )
  
      def test_get_metric_history_daily(self):
          """Tests ``R.get_metric_history`` with daily granularity."""
          self._test_get_metric_history('test-slug', granularity='daily')
  
          # with specified to/since dates
          self._test_get_metric_history(
              'test-slug',
              since=datetime(2014, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='daily'
          )
  
      def test_get_metric_history_weekly(self):
          """Tests ``R.get_metric_history`` with weekly granularity."""
          self._test_get_metric_history('test-slug', granularity='weekly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              'test-slug',
              since=datetime(2014, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='weekly'
          )
  
      def test_get_metric_history_monthly(self):
          """Tests ``R.get_metric_history`` with monthly granularity."""
          self._test_get_metric_history('test-slug', granularity='monthly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              'test-slug',
              since=datetime(2014, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='monthly'
          )
  
      def test_get_metric_history_yearly(self):
          """Tests ``R.get_metric_history`` with yearly granularity."""
          self._test_get_metric_history('test-slug', granularity='yearly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              'test-slug',
              since=datetime(2014, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='yearly'
          )
  
      def test_get_metric_multiple_history_hourly(self):
          self._test_get_metric_history(['foo', 'bar'], granularity='hourly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              ['foo', 'bar'],
              since=datetime(2015, 1, 1),
              to=datetime(2015, 2, 1),
              granularity='hourly'
          )
  
      def test_get_metric_multiple_history_daily(self):
          self._test_get_metric_history(['foo', 'bar'], granularity='daily')
  
          # with specified to/since dates
          self._test_get_metric_history(
              ['foo', 'bar'],
              since=datetime(2015, 1, 1),
              to=datetime(2015, 2, 1),
              granularity='daily'
          )
  
      def test_get_metric_multiple_history_weekly(self):
          self._test_get_metric_history(['foo', 'bar'], granularity='weekly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              ['foo', 'bar'],
              since=datetime(2015, 1, 1),
              to=datetime(2015, 2, 1),
              granularity='weekly'
          )
  
      def test_get_metric_multiple_history_monthly(self):
          self._test_get_metric_history(['foo', 'bar'], granularity='monthly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              ['foo', 'bar'],
              since=datetime(2015, 1, 1),
              to=datetime(2015, 12, 1),
              granularity='monthly'
          )
  
      def test_get_metric_multiple_history_yearly(self):
          self._test_get_metric_history(['foo', 'bar'], granularity='yearly')
  
          # with specified to/since dates
          self._test_get_metric_history(
              ['foo', 'bar'],
              since=datetime(2015, 1, 1),
              to=datetime(2016, 1, 1),
              granularity='yearly'
          )
  
      @patch.object(R, '_date_range')
      def test_get_metric_history_replaces_none_with_zero(self, mock_date_range):
          """Ensure that None-values get replaced with Zeros in
          ``R.get_metric_history``."""
  
          # Mock the _date_range method so we can specify it's return values.
          mock_date_range.return_value = [
              datetime(2000, 1, 1),
              datetime(2000, 1, 2),
              datetime(2000, 1, 3),
              datetime(2000, 1, 4),
          ]
  
          # Temporarily change the return value for mget
          mget_return = self.redis.mget.return_value
          self.redis.mget.return_value = ['1', '2', None, '3']
  
          # Note: we're not providing a since parameter here, since we've
          # mocked the R._date_range method.
          results = self.r.get_metric_history("foo", granularity="daily")
  
          # Format the range of dates that for which we should get results
          expected = [
              ('m:foo:2000-01-01', '1'),
              ('m:foo:2000-01-02', '2'),
              ('m:foo:2000-01-03', 0),
              ('m:foo:2000-01-04', '3'),
          ]
          self.assertEqual(results, expected)
  
          # Reset mget's previous return value
          self.redis.mget.return_value = mget_return
  
      @patch.object(R, 'get_metric_history')
      def test_get_metric_history_as_columns(self, mock_metric_hist):
          # set up some sample (yearly) metrics
          mock_metric_hist.return_value = [
              ("m:bar:y:2012", '1'),
              ('m:bar:y:2013', '2'),
              ('m:foo:y:2012', '3'),
              ('m:foo:y:2013', '4'),
          ]
          expected_results = [
              ('Period', 'foo', 'bar'),
              ('y:2012', '3', '1'),
              ('y:2013', '4', '2'),
          ]
          with patch('redis_metrics.models.redis.StrictRedis'):
              r = R()
              kwargs = {
                  'slugs': ['foo', 'bar'],
                  'since': None,
                  'granularity': 'yearly',
              }
              results = r.get_metric_history_as_columns(**kwargs)
              self.assertEqual(results, expected_results)
  
      def _test_get_metric_history_as_columns(self, slugs, granularity):
          """Test that R.get_metric_history_as_columns makes calls to the
          following functions:
  
          * ``R.r.mget``
          * ``R.get_metric_history``
          * ``templatetags.metric_slug``
          * ``templatetags.strip_metric_prefix``
  
          """
          keys = self._metric_history_keys(slugs, granularity=granularity)
          self.r.get_metric_history_as_columns(slugs, granularity=granularity)
  
          # Verifies the correct call to redis
          self.redis.assert_has_calls([call.mget(keys)])
  
          # Verify that the method gets called correctly
          with patch('redis_metrics.models.R') as mock_r:
              r = mock_r.return_value  # Get an instance of our Mocked R class
              r.get_metric_history_as_columns(slugs, granularity=granularity)
              mock_r.assert_has_calls([
                  call().get_metric_history_as_columns(
                      slugs, granularity=granularity
                  )
              ])
  
      def test_get_metric_history_as_columns_hourly(self):
          self._test_get_metric_history_as_columns(['foo', 'bar'], 'hourly')
  
      def test_get_metric_history_as_columns_daily(self):
          self._test_get_metric_history_as_columns(['foo', 'bar'], 'daily')
  
      def test_get_metric_history_as_columns_weekly(self):
          self._test_get_metric_history_as_columns(['foo', 'bar'], 'weekly')
  
      def test_get_metric_history_as_columns_monthly(self):
          self._test_get_metric_history_as_columns(['foo', 'bar'], 'monthly')
  
      def test_get_metric_history_as_columns_yearly(self):
          self._test_get_metric_history_as_columns(['foo', 'bar'], 'yearly')
  
      @patch.object(R, 'get_metric_history')
      def test_get_metric_history_chart_data(self, mock_metric_hist):
          # set up some sample (yearly) metrics
          mock_metric_hist.return_value = [
              ("m:bar:y:2012", '1'),
              ('m:bar:y:2013', '2'),
              ('m:foo:y:2012', '3'),
              ('m:foo:y:2013', '4'),
          ]
          expected_results = {
              'periods': ['y:2012', 'y:2013'],
              'data': [
                  {'slug': 'bar', 'values': ['1', '2']},
                  {'slug': 'foo', 'values': ['3', '4']},
              ]
          }
          with patch('redis_metrics.models.redis.StrictRedis'):
              r = R()
              kwargs = {
                  'slugs': ['foo', 'bar'],
                  'since': None,
                  'granularity': 'yearly',
              }
              results = r.get_metric_history_chart_data(**kwargs)
              self.assertEqual(results, expected_results)
  
      def test_gauge_slugs(self):
          """Tests that ``R.gauge_slugs`` calls the SMEMBERS command."""
          self.r.gauge_slugs()
          self.redis.assert_has_calls([call.smembers(self.r._gauge_slugs_key)])
  
      def test__gauge_key(self):
          """Tests that ``R._gauge_key`` correctly generates gauge keys."""
          key = self.r._gauge_key('test-gauge')
          self.assertEqual(key, 'g:test-gauge')
  
      def test_gauge(self):
          """Tests setting a gauge with ``R.gauge``. Verifies that the gauge slug
          is added to the set of gauge slugs and that the value gets set."""
          self.r.gauge('test-gauge', 9000)
          self.redis.assert_has_calls([
              call.sadd(self.r._gauge_slugs_key, 'test-gauge'),
              call.set('g:test-gauge', 9000),
          ])
  
      def test_get_gauge(self):
          """Tests retrieving a gague with ``R.get_gauge``. Verifies that the
          Redis GET command is called with the correct key."""
          self.r.get_gauge('test-gauge')
          self.redis.assert_has_calls([call.get('g:test-gauge')])
  
      def test_delete_gauge(self):
          """Tests deltion of a gauge."""
          self.r.delete_gauge("test-gauge")
          self.redis.assert_has_calls([
              call.delete('g:test-gauge'),
              call.srem(self.r._gauge_slugs_key, "test-gauge"),
          ])
  