<commit_before>"""
Tests the models of the organization application
"""
# pylint: disable=no-member

from django.test import TestCase

from mock import Mock, patch
import nose.tools

import muckrock.factories
from muckrock.settings import ORG_MIN_SEATS,\
                              ORG_PRICE_PER_SEAT,\
                              ORG_REQUESTS_PER_SEAT

ok_ = nose.tools.ok_
eq_ = nose.tools.eq_

# Creates mock items for testing methods that involve Stripe
mock_subscription = Mock()
mock_subscription.id = 'test-org-subscription'
mock_subscription.save.return_value = mock_subscription
mock_customer = Mock()
mock_customer.subscriptions.create.return_value = mock_subscription
mock_customer.subscriptions.retrieve.return_value = mock_subscription
MockCustomer = Mock()
MockCustomer.create.return_value = mock_customer
MockCustomer.retrieve.return_value = mock_customer
mock_plan = Mock()
mock_plan.amount = 100
mock_plan.name = 'Organization'
mock_plan.id = 'org'
MockPlan = Mock()
MockPlan.create.return_value = mock_plan
MockPlan.retrieve.return_value = mock_plan


class TestRations(TestCase):
    """Test the dynamic rationing of seats, monthly cost, and monthly requests."""
    def setUp(self):
        """Create a basic organization"""
        self.org = muckrock.factories.OrganizationFactory()

    def test_no_change(self):
        """If the seats do not change, then the cost and requests shouldn't change."""
        num_seats = self.org.max_users
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost,
            'The monthly cost should not change if the number of seats stays the same.')
        eq_(self.org.monthly_requests, old_monthly_requests,
            'The monthly requests should not change if the number of seats stays the same.')

    def test_increase(self):
        """If the seats increase, then the cost and requests should also increase."""
        seat_increase = 1
        cost_increase = ORG_PRICE_PER_SEAT * seat_increase
        request_increase = ORG_REQUESTS_PER_SEAT * seat_increase
        num_seats = self.org.max_users + seat_increase
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost + cost_increase,
            'The monthly cost should increase based on the old cost.')
        eq_(self.org.monthly_requests, old_monthly_requests + request_increase,
            'The monhtly requests should increase based on the old requests.')

    def test_decrease(self):
        """If the seats decrease, then the cost and requests should also decrease."""
        seat_decrease = -1
        cost_decrease = ORG_PRICE_PER_SEAT * seat_decrease
        request_decrease = ORG_REQUESTS_PER_SEAT * seat_decrease
        num_seats = self.org.max_users + seat_decrease
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost + cost_decrease,
            'The monthly cost should decrease based on the old cost.')
        eq_(self.org.monthly_requests, old_monthly_requests + request_decrease,
            'The monhtly requests should decrease based on the old requests.')


# Substitutes mock items for Stripe items in each test
@patch('stripe.Customer', MockCustomer)
@patch('stripe.Plan', MockPlan)
class TestSubscriptions(TestCase):
    """Test the methods for activating, updating, and cancelling an org subscription."""
    def setUp(self):
        """Create a basic organization"""
        self.org = muckrock.factories.OrganizationFactory()
        ok_(not self.org.active and not self.org.stripe_id,
            'By default, an org should be inactive and subscription-less')

    def test_activation(self):
        """Activating the organization should subscribe the owner to an org plan."""
        # pylint: disable=line-too-long
        # pylint disabled because 1 character r u kidding me
        # lets add an extra seat, just to make things interesting
        seat_increase = 1
        expected_cost_increase = self.org.monthly_cost + ORG_PRICE_PER_SEAT * seat_increase
        expected_request_increase = self.org.monthly_requests + ORG_REQUESTS_PER_SEAT * seat_increase
        num_seats = self.org.max_users + seat_increase
        self.org.activate_subscription('test', num_seats)
        eq_(self.org.max_users, num_seats,
            'The maximum number of users should be updated.')
        eq_(self.org.monthly_cost, expected_cost_increase,
            'The monthly cost should be updated.')
        eq_(self.org.monthly_requests, expected_request_increase,
            'The monthly requests should be updated.')
        eq_(self.org.stripe_id, mock_subscription.id,
            'The subscription ID should be saved to the organization.')
        ok_(self.org.active,
            'The org should be set to an active state.')

    @nose.tools.raises(ValueError)
    def test_activate_min_seats(self):
        """Activating with less than the minimum number of seats should raise an error."""
        self.org.activate_subscription('test', ORG_MIN_SEATS - 1)

    @nose.tools.raises(AttributeError)
    def test_activate_active_org(self):
        """Activating and active organization should raise an error."""
        self.org.active = True
        self.org.save()
        self.org.activate_subscription('test', ORG_MIN_SEATS)

    def test_updating(self):
        """Updating the subscription should update the quantity of the subscription."""
        # pylint: disable=line-too-long
        # pylint disabled because 1 character r u kidding me
        # change the stripe_id to something else, to make sure it gets updated
        self.org.stripe_id = 'temp'
        self.org.active = True
        self.org.save()
        # let's update this org with 2 more seats
        seat_increase = 2
        expected_cost_increase = self.org.monthly_cost + ORG_PRICE_PER_SEAT * seat_increase
        expected_request_increase = self.org.monthly_requests + ORG_REQUESTS_PER_SEAT * seat_increase
        expected_quantity = expected_cost_increase / 100
        num_seats = self.org.max_users + seat_increase
        self.org.update_subscription(num_seats)
        eq_(self.org.monthly_cost, expected_cost_increase,
            'The monthly cost should be updated.')
        eq_(self.org.monthly_requests, expected_request_increase,
            'The monthly requests should be updated.')
        eq_(self.org.max_users, num_seats,
            'The maximum number of users should be updated.')
        eq_(mock_subscription.quantity, expected_quantity,
            'The subscription quantity should be based on the monthly cost.')
        eq_(self.org.stripe_id, mock_subscription.id,
            'The subscription ID should be saved to the organization.')
        ok_(self.org.active,
            'The org should be set to an active state.')

    @nose.tools.raises(ValueError)
    def test_update_min_seats(self):
        """Activating with less than the minimum number of seats should raise an error."""
        self.org.active = True
        self.org.save()
        self.org.update_subscription(ORG_MIN_SEATS - 1)

    @nose.tools.raises(AttributeError)
    def test_update_inactive(self):
        """Updating an inactive organization should raise an error."""
        ok_(not self.org.active)
        self.org.update_subscription(ORG_MIN_SEATS)

    def test_cancelling(self):
        """Cancelling the subscription should render the org inactive."""
        self.org.active = True
        self.org.save()
        self.org.cancel_subscription()
        ok_(not self.org.active,
            'The organization should be set to an inactive state.')
        ok_(not self.org.stripe_id,
            'The stripe subscription ID should be removed from the org.')

    @nose.tools.raises(AttributeError)
    def test_cancel_inactive(self):
        """Cancelling an inactive subscription should throw an error."""
        ok_(not self.org.active)
        self.org.cancel_subscription()


class TestMembership(TestCase):
    """Test the membership functions of the organization"""
    def setUp(self):
        """Create an owner, a member, and an organization"""
        self.org = muckrock.factories.OrganizationFactory(active=True)
        self.owner = self.org.owner
        self.member = muckrock.factories.UserFactory(profile__organization=self.org)
<commit_msg>broken tests for stripe payments<commit_after>"""
Tests the models of the organization application
"""
# pylint: disable=no-member

from django.test import TestCase

from mock import Mock, patch
import nose.tools
import stripe

import muckrock.factories
from muckrock.settings import ORG_MIN_SEATS,\
                              ORG_PRICE_PER_SEAT,\
                              ORG_REQUESTS_PER_SEAT

ok_ = nose.tools.ok_
eq_ = nose.tools.eq_

# Creates mock items for testing methods that involve Stripe
mock_subscription = Mock()
mock_subscription.id = 'test-org-subscription'
mock_subscription.save.return_value = mock_subscription
mock_customer = Mock()
mock_customer.subscriptions.create.return_value = mock_subscription
mock_customer.subscriptions.retrieve.return_value = mock_subscription
MockCustomer = Mock()
MockCustomer.create.return_value = mock_customer
MockCustomer.retrieve.return_value = mock_customer
mock_plan = Mock()
mock_plan.amount = 100
mock_plan.name = 'Organization'
mock_plan.id = 'org'
MockPlan = Mock()
MockPlan.create.return_value = mock_plan
MockPlan.retrieve.return_value = mock_plan


class TestRations(TestCase):
    """Test the dynamic rationing of seats, monthly cost, and monthly requests."""
    def setUp(self):
        """Create a basic organization"""
        self.org = muckrock.factories.OrganizationFactory()

    def test_no_change(self):
        """If the seats do not change, then the cost and requests shouldn't change."""
        num_seats = self.org.max_users
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost,
            'The monthly cost should not change if the number of seats stays the same.')
        eq_(self.org.monthly_requests, old_monthly_requests,
            'The monthly requests should not change if the number of seats stays the same.')

    def test_increase(self):
        """If the seats increase, then the cost and requests should also increase."""
        seat_increase = 1
        cost_increase = ORG_PRICE_PER_SEAT * seat_increase
        request_increase = ORG_REQUESTS_PER_SEAT * seat_increase
        num_seats = self.org.max_users + seat_increase
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost + cost_increase,
            'The monthly cost should increase based on the old cost.')
        eq_(self.org.monthly_requests, old_monthly_requests + request_increase,
            'The monhtly requests should increase based on the old requests.')

    def test_decrease(self):
        """If the seats decrease, then the cost and requests should also decrease."""
        seat_decrease = -1
        cost_decrease = ORG_PRICE_PER_SEAT * seat_decrease
        request_decrease = ORG_REQUESTS_PER_SEAT * seat_decrease
        num_seats = self.org.max_users + seat_decrease
        old_monthly_cost = self.org.monthly_cost
        old_monthly_requests = self.org.monthly_requests
        self.org.update_num_seats(num_seats)
        eq_(self.org.monthly_cost, old_monthly_cost + cost_decrease,
            'The monthly cost should decrease based on the old cost.')
        eq_(self.org.monthly_requests, old_monthly_requests + request_decrease,
            'The monhtly requests should decrease based on the old requests.')


# Substitutes mock items for Stripe items in each test
@patch('stripe.Customer', MockCustomer)
@patch('stripe.Plan', MockPlan)
class TestSubscriptions(TestCase):
    """Test the methods for activating, updating, and cancelling an org subscription."""
    def setUp(self):
        """Create a basic organization"""
        self.org = muckrock.factories.OrganizationFactory()
        ok_(not self.org.active and not self.org.stripe_id,
            'By default, an org should be inactive and subscription-less')

    def test_activation(self):
        """Activating the organization should subscribe the owner to an org plan."""
        # pylint: disable=line-too-long
        # pylint disabled because 1 character r u kidding me
        # lets add an extra seat, just to make things interesting
        seat_increase = 1
        expected_cost_increase = self.org.monthly_cost + ORG_PRICE_PER_SEAT * seat_increase
        expected_request_increase = self.org.monthly_requests + ORG_REQUESTS_PER_SEAT * seat_increase
        num_seats = self.org.max_users + seat_increase
        self.org.activate_subscription('test', num_seats)
        eq_(self.org.max_users, num_seats,
            'The maximum number of users should be updated.')
        eq_(self.org.monthly_cost, expected_cost_increase,
            'The monthly cost should be updated.')
        eq_(self.org.monthly_requests, expected_request_increase,
            'The monthly requests should be updated.')
        eq_(self.org.stripe_id, mock_subscription.id,
            'The subscription ID should be saved to the organization.')
        ok_(self.org.active,
            'The org should be set to an active state.')

    @nose.tools.raises(ValueError)
    def test_activate_min_seats(self):
        """Activating with less than the minimum number of seats should raise an error."""
        self.org.activate_subscription('test', ORG_MIN_SEATS - 1)

    @nose.tools.raises(AttributeError)
    def test_activate_active_org(self):
        """Activating and active organization should raise an error."""
        self.org.active = True
        self.org.save()
        self.org.activate_subscription('test', ORG_MIN_SEATS)

    def test_updating(self):
        """Updating the subscription should update the quantity of the subscription."""
        # pylint: disable=line-too-long
        # pylint disabled because 1 character r u kidding me
        # change the stripe_id to something else, to make sure it gets updated
        self.org.stripe_id = 'temp'
        self.org.active = True
        self.org.save()
        # let's update this org with 2 more seats
        seat_increase = 2
        expected_cost_increase = self.org.monthly_cost + ORG_PRICE_PER_SEAT * seat_increase
        expected_request_increase = self.org.monthly_requests + ORG_REQUESTS_PER_SEAT * seat_increase
        expected_quantity = expected_cost_increase / 100
        num_seats = self.org.max_users + seat_increase
        self.org.update_subscription(num_seats)
        eq_(self.org.monthly_cost, expected_cost_increase,
            'The monthly cost should be updated.')
        eq_(self.org.monthly_requests, expected_request_increase,
            'The monthly requests should be updated.')
        eq_(self.org.max_users, num_seats,
            'The maximum number of users should be updated.')
        eq_(mock_subscription.quantity, expected_quantity,
            'The subscription quantity should be based on the monthly cost.')
        eq_(self.org.stripe_id, mock_subscription.id,
            'The subscription ID should be saved to the organization.')
        ok_(self.org.active,
            'The org should be set to an active state.')

    @nose.tools.raises(ValueError)
    def test_update_min_seats(self):
        """Activating with less than the minimum number of seats should raise an error."""
        self.org.active = True
        self.org.save()
        self.org.update_subscription(ORG_MIN_SEATS - 1)

    @nose.tools.raises(AttributeError)
    def test_update_inactive(self):
        """Updating an inactive organization should raise an error."""
        ok_(not self.org.active)
        self.org.update_subscription(ORG_MIN_SEATS)

    def test_cancelling(self):
        """Cancelling the subscription should render the org inactive."""
        self.org.active = True
        self.org.save()
        self.org.cancel_subscription()
        ok_(not self.org.active,
            'The organization should be set to an inactive state.')
        ok_(not self.org.stripe_id,
            'The stripe subscription ID should be removed from the org.')

    @nose.tools.raises(AttributeError)
    def test_cancel_inactive(self):
        """Cancelling an inactive subscription should throw an error."""
        ok_(not self.org.active)
        self.org.cancel_subscription()


# actually tests Stripe code
class TestStripe(TestCase):
    """
    Test Stripe integration for activate, update, and cancel methods.
    Mainly checking for errors on calls to SDK methods.
    """
    def setUp(self):
        self.org = muckrock.factories.OrganizationFactory()
        self.token = self.get_stripe_token()

    def test_methods(self):
        """Test the subscription methods."""
        self.org.activate_subscription(self.token, self.org.max_users)
        self.org.update_subscription(max_users + 1)
        self.org.cancel_subscription()

    def get_stripe_token(self):
        """
        Helper function for creating a dummy Stripe token.
        Normally, the token would be generated by Stripe Checkout on the front end.
        """
        token = stripe.Token.create(
            card={
                "number": '4242424242424242',
                "exp_month": 12,
                "exp_year": 2016,
                "cvc": '123'
        })
        ok_(token)
        return token.id


class TestMembership(TestCase):
    """Test the membership functions of the organization"""
    def setUp(self):
        """Create an owner, a member, and an organization"""
        self.org = muckrock.factories.OrganizationFactory(active=True)
        self.owner = self.org.owner
        self.member = muckrock.factories.UserFactory(profile__organization=self.org)

{'fraction_non_alphanumeric': 0.08141814617144102, 'fraction_numerical': 0.0030497767127763862, 'mean_word_length': 3.0015253867945084, 'pattern_counts': {'":': 4, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2482320', 'n_tokens_mistral': 5405, 'n_tokens_neox': 5208, 'n_words': 1434}