Beispiel #1
0
    def test_all_features_with_data(self):
        """ Tests that the method returns the correct data with
        activated features.
        """
        feature1 = Feature('looktest1')
        feature1.set_percentage(5)

        feature2 = Feature('looktest2')
        feature2.activate()
        feature2.add_to_whitelist(3)

        feature3 = Feature('looktest3')
        feature3.activate()
        feature3.add_to_blacklist(4)
        feature3.add_to_blacklist(5)

        feature4 = Feature('looktest4')
        feature4.activate()
        feature4.add_to_whitelist(3)
        feature4.add_to_whitelist(5)
        feature4.add_to_blacklist(4)

        all_features = Feature.all_features(include_data=True)
        self.assertEqual(len(all_features), 4)

        for key in ['looktest1', 'looktest2', 'looktest3', 'looktest4']:
            self.assertTrue(key in all_features)
            if not key == 'looktest1':
                self.assertEqual(all_features[key]['percentage'], 100)

        self.assertEqual(all_features['looktest1']['percentage'], 5)
        self.assertFalse('whitelist' in all_features['looktest1'])
        self.assertFalse('blacklist' in all_features['looktest1'])

        self.assertTrue('whitelist' in all_features['looktest2'])
        self.assertEqual(all_features['looktest2']['whitelist'], [3])
        self.assertFalse('blacklist' in all_features['looktest2'])

        self.assertFalse('whitelist' in all_features['looktest3'])
        self.assertTrue('blacklist' in all_features['looktest3'])
        self.assertEqual(all_features['looktest3']['blacklist'], [4, 5])

        self.assertTrue('whitelist' in all_features['looktest4'])
        self.assertEqual(all_features['looktest4']['whitelist'], [3, 5])
        self.assertTrue('blacklist' in all_features['looktest4'])
        self.assertEqual(all_features['looktest4']['blacklist'], [4])
Beispiel #2
0
class FeatureTest(unittest.TestCase):
    """ Tests the feature ramping system in Redis. """
    def setUp(self):
        redis_conn = redis.StrictRedis(host='localhost', port=6379, db=0)
        cloak.initialize(redis_conn)
        self.feature_test = Feature("testing")

    def tearDown(self):
        for feature in Feature.all_features():
            Feature(feature).delete()

    def test_initialize_feature_with_default_percentage(self):
        feature_test = Feature("testing", default_percentage=100)

        self.assertEquals(feature_test.percentage, 100)

    def test_reset_settings(self):
        """ Tests calling reset_settings resets the correct
        data and updates it in Redis. """

        self.feature_test.set_percentage(5)
        self.feature_test.add_to_whitelist(3)
        self.feature_test.add_to_blacklist(4)
        self.feature_test.reset_settings()

        generated = Feature("testing")
        self.assertEqual(generated.percentage, 0)
        self.assertFalse(3 in generated.whitelist)
        self.assertFalse(4 in generated.blacklist)

    def test_delete(self):
        """ Tests that calling delete removes the data from Redis. """

        self.feature_test.set_percentage(5)
        self.feature_test.delete()
        key = self.feature_test._get_redis_key()
        redis_data = cloak.redis.get(key)
        self.assertTrue(redis_data is None)

        set_key = Feature._get_redis_set_key()
        self.assertFalse(cloak.redis.sismember(set_key, key))

    def test_all_features(self):
        """ Tests that the method returns a list of all feature
        names activated.
        """
        to_create = ['looktest1', 'looktest2', 'looktest3']
        for f in to_create:
            Feature(f).activate()

        all_features = Feature.all_features()
        self.assertEqual(len(all_features), len(to_create))
        for f in to_create:
            self.assertTrue(f in all_features)

    def test_all_features_with_data(self):
        """ Tests that the method returns the correct data with
        activated features.
        """
        feature1 = Feature('looktest1')
        feature1.set_percentage(5)

        feature2 = Feature('looktest2')
        feature2.activate()
        feature2.add_to_whitelist(3)

        feature3 = Feature('looktest3')
        feature3.activate()
        feature3.add_to_blacklist(4)
        feature3.add_to_blacklist(5)

        feature4 = Feature('looktest4')
        feature4.activate()
        feature4.add_to_whitelist(3)
        feature4.add_to_whitelist(5)
        feature4.add_to_blacklist(4)

        all_features = Feature.all_features(include_data=True)
        self.assertEqual(len(all_features), 4)

        for key in ['looktest1', 'looktest2', 'looktest3', 'looktest4']:
            self.assertTrue(key in all_features)
            if not key == 'looktest1':
                self.assertEqual(all_features[key]['percentage'], 100)

        self.assertEqual(all_features['looktest1']['percentage'], 5)
        self.assertFalse('whitelist' in all_features['looktest1'])
        self.assertFalse('blacklist' in all_features['looktest1'])

        self.assertTrue('whitelist' in all_features['looktest2'])
        self.assertEqual(all_features['looktest2']['whitelist'], [3])
        self.assertFalse('blacklist' in all_features['looktest2'])

        self.assertFalse('whitelist' in all_features['looktest3'])
        self.assertTrue('blacklist' in all_features['looktest3'])
        self.assertEqual(all_features['looktest3']['blacklist'], [4, 5])

        self.assertTrue('whitelist' in all_features['looktest4'])
        self.assertEqual(all_features['looktest4']['whitelist'], [3, 5])
        self.assertTrue('blacklist' in all_features['looktest4'])
        self.assertEqual(all_features['looktest4']['blacklist'], [4])

    def test_set_add(self):
        """ Tests that creating a feature stores its key in a Redis set. """

        self.feature_test.set_percentage(15)
        key = self.feature_test._get_redis_key()
        set_key = Feature._get_redis_set_key()
        self.assertTrue(cloak.redis.sismember(set_key, key))

    def test_set_percentage(self):
        """ Tests calling set_percentage sets the correct
        data in Redis. """

        self.feature_test.set_percentage(5)
        self.assertEqual(Feature("testing").percentage, 5)

    def test_set_float_percentage(self):
        """ Tests that calling set_percentage() with a float truncates
        to int.
        """

        self.feature_test.set_percentage(50.5)
        self.assertEqual(self.feature_test.percentage, 50)

    def test_set_string_percentage(self):
        """ Tests that calling set_percentage() with a string converts it to
        an int if possible.
        """

        self.feature_test.set_percentage("50")
        self.assertEqual(self.feature_test.percentage, 50)
        self.assertTrue(isinstance(self.feature_test.percentage, int))

    def test_set_invalid_string_percentage(self):
        """ Tests that calling set_percentage() on an invalid percentage
        raises ValueError.
        """

        with self.assertRaises(ValueError):
            self.feature_test.set_percentage("meow")

    def test_add_to_whitelist(self):
        """ Tests calling add_to_whitelist sets the correct
        data in Redis. """

        self.feature_test.add_to_whitelist(3)
        self.assertTrue(3 in Feature("testing").whitelist)

    def test_add_to_whitelist_with_string(self):
        """ Tests calling add_to_whitelist sets the correct
        data in Redis when using a string. """
        email = '*****@*****.**'
        self.feature_test.add_to_whitelist(email)
        self.assertTrue(email in Feature("testing").whitelist)

    def test_remove_from_whitelist(self):
        """ Tests calling remove_from_whitelist sets the correct
        data in Redis. """

        self.feature_test.add_to_whitelist(3)
        self.feature_test.remove_from_whitelist(3)
        self.assertFalse(3 in Feature("testing").whitelist)

    def test_remove_from_whitelist_with_string(self):
        """ Tests calling remove_from_whitelist using string sets the correct
        data in Redis. """
        email = '*****@*****.**'
        self.feature_test.add_to_whitelist(email)
        self.feature_test.remove_from_whitelist(email)
        self.assertFalse(email in Feature("testing").whitelist)

    def test_add_to_blacklist(self):
        """ Tests calling add_to_blacklist sets the correct
        data in Redis. """

        self.feature_test.add_to_blacklist(3)
        self.assertTrue(3 in Feature("testing").blacklist)

    def test_add_to_blacklist_with_string(self):
        """ Tests calling add_to_blacklist sets the correct
        data in Redis when using a string. """
        email = '*****@*****.**'
        self.feature_test.add_to_blacklist(email)
        self.assertTrue(email in Feature("testing").blacklist)

    def test_remove_from_blacklist(self):
        """ Tests calling remove_from_blacklist sets the correct
        data in Redis. """

        self.feature_test.add_to_blacklist(3)
        self.feature_test.remove_from_blacklist(3)
        self.assertFalse(3 in Feature("testing").blacklist)

    def test_remove_from_blacklist_with_string(self):
        """ Tests calling remove_from_blacklist using string sets the correct
        data in Redis. """
        email = '*****@*****.**'
        self.feature_test.add_to_blacklist(email)
        self.feature_test.remove_from_blacklist(email)
        self.assertFalse(email in Feature("testing").blacklist)

    def test_active_off(self):
        """ Tests calling is_active is correct when off. """

        self.feature_test.set_percentage(0)
        self.assertFalse(self.feature_test.is_active)

    def test_active_on(self):
        """ Tests calling is_active is correct when on. """

        self.feature_test.set_percentage(100)
        self.assertTrue(self.feature_test.is_active)

    def test_visible_whitelisted(self):
        """ Tests calling is_visible is correct when whitelisted. """

        self.feature_test.set_percentage(0)
        self.feature_test.add_to_whitelist(3)
        self.assertTrue(self.feature_test.is_visible(3))

    def test_visible_whitelisted_with_string(self):
        """ Tests calling is_visible with string is correct
        when whitelisted.
        """
        email = '*****@*****.**'
        self.feature_test.set_percentage(0)
        self.feature_test.add_to_whitelist(email)
        self.assertTrue(self.feature_test.is_visible(email))

    def test_visible_blacklisted(self):
        """ Tests calling is_visible is correct when blacklisted. """

        self.feature_test.set_percentage(100)
        self.feature_test.add_to_blacklist(3)
        self.assertFalse(self.feature_test.is_visible(3))

    def test_visible_blacklisted_with_string(self):
        """ Tests calling is_visible with string is correct
        when blacklisted.
        """
        email = '*****@*****.**'
        self.feature_test.set_percentage(0)
        self.feature_test.add_to_blacklist(email)
        self.assertFalse(self.feature_test.is_visible(email))

    def test_visible_white_and_blacklisted(self):
        """ Tests calling is_visible is correct when both white
        and blacklisted.
        """

        self.feature_test.set_percentage(0)
        self.feature_test.add_to_whitelist(3)
        self.feature_test.add_to_blacklist(3)
        self.assertTrue(self.feature_test.is_visible(3))

    def test_visible_white_and_blacklisted_with_string(self):
        """ Tests calling is_visible is correct when both white
        and blacklisted.
        """
        email = '*****@*****.**'
        self.feature_test.set_percentage(0)
        self.feature_test.add_to_whitelist(email)
        self.feature_test.add_to_blacklist(email)
        self.assertTrue(self.feature_test.is_visible(email))

    def test_visible_ramp(self):
        """ Tests calling is_visible is correct when partially ramped. """
        total_number = 100000
        expected_percentage = .10
        self.feature_test.set_percentage(expected_percentage * 100)
        # Generate a range of user ids and map these ids to the feature
        # test result.
        user_ids = list(range(1, total_number + 1))
        visibility_map = [
            self.feature_test.is_visible(user_id) for user_id in user_ids
        ]
        # Count the number of success conditions.
        visibility_count = visibility_map.count(True)
        # This should match 10%.
        actual_percentage = visibility_count / float(total_number)
        self.assertAlmostEqual(actual_percentage,
                               expected_percentage,
                               delta=.012)

    def test_visible_ramp_using_string(self):
        """Tests calling is_visible when using string as identifier is
        correct when partially ramped.
        """
        try:
            lowercase_letters = string.ascii_lowercase
        except AttributeError:
            lowercase_letters = string.lowercase

        identifiers = list(itertools.product(lowercase_letters, repeat=3))
        total_number = len(identifiers)
        expected_percentage = .10
        self.feature_test.set_percentage(expected_percentage * 100)
        # Generate a range of user ids and map these ids to the feature
        # test result.
        visibility_map = [
            self.feature_test.is_visible(identifier)
            for identifier in identifiers
        ]
        # Count the number of success conditions.
        visibility_count = visibility_map.count(True)
        # This should match 10%.
        actual_percentage = visibility_count / float(total_number)
        self.assertAlmostEqual(actual_percentage,
                               expected_percentage,
                               delta=.012)

    def test_is_ramped_using_int(self):
        """Tests that _is_ramped accepts integers as identifer."""
        self.feature_test.set_percentage(100)
        self.assertTrue(self.feature_test._is_ramped(5))

    def test_is_ramped_using_string(self):
        """Tests that _is_ramped accepts strings as identifier."""
        self.feature_test.set_percentage(100)
        self.assertTrue(self.feature_test._is_ramped('*****@*****.**'))

    def test_is_ramped_using_unicode_string(self):
        """Tests that _is_ramped accepts unicode strings as identifier."""
        self.feature_test.set_percentage(100)
        self.assertTrue(self.feature_test._is_ramped(u'\[email protected]'))

    def test_redis_key(self):
        """ Tests the redis key builder returns the expected string. """

        generated = self.feature_test._get_redis_key()
        expected = "feature.1.testing"
        self.assertEqual(generated, expected)

    def test_group_names(self):
        feature_one = Feature('feature_one', feature_group_name='test_group')
        feature_two = Feature('feature_two', feature_group_name='test_group')

        feature_one.set_percentage(10)
        feature_two.set_percentage(10)

        identifiers = list(range(1, 10001))

        visibility_test_one = [
            id for id in identifiers if feature_one.is_visible(id)
        ]

        visibility_test_two = [
            id for id in identifiers if feature_two.is_visible(id)
        ]

        self.assertEqual(visibility_test_one, visibility_test_two)