Esempio n. 1
0
    def create(self, validated_data):
        """Create a user from validated data."""
        user = None
        tenant = None
        request = self.context.get('request')
        if request and hasattr(request, 'META'):
            json_rh_auth = extract_header(request, RH_IDENTITY_HEADER)
            if (json_rh_auth and 'identity' in json_rh_auth and  # noqa: W504
                    'account_number' in json_rh_auth['identity']):
                account = json_rh_auth['identity']['account_number']
            if account:
                schema_name = create_schema_name(account)
                try:
                    tenant = Tenant.objects.get(schema_name=schema_name)
                except Tenant.DoesNotExist:
                    tenant = Tenant(schema_name=schema_name)
                    tenant.save()
                    tenant = Tenant.objects.get(schema_name=schema_name)
            else:
                key = 'detail'
                message = 'Tenant for requesting user could not be found.'
                raise serializers.ValidationError(error_obj(key, message))

        user = _create_user(username=validated_data.get('username'),
                            email=validated_data.get('email'),
                            tenant=tenant)

        return user
Esempio n. 2
0
    def _create_customer(cls, account, create_tenant=True):
        """Create a customer.

        Args:
            account (str): The account identifier

        Returns:
            (Customer) The created customer

        """
        connection.set_schema_to_public()
        schema_name = create_schema_name(account)
        tenant = None
        if create_tenant:
            tenant = Tenant(schema_name=schema_name)
            tenant.save()
        return tenant
Esempio n. 3
0
    def _create_tenant(account):
        """Create a tenant.

        Args:
            account (str): The account identifier

        Returns:
            (Tenant) The created tenant

        """
        schema_name = create_schema_name(account)
        try:
            with transaction.atomic():
                tenant = Tenant(schema_name=schema_name)
                tenant.save()
                logger.info('Created new tenant from account_id %s.', account)
        except IntegrityError:
            tenant = Tenant.objects.filter(schema_name=schema_name).get()

        return tenant
Esempio n. 4
0
class ReportQueryTest(IamTestCase):
    """Tests the report queries."""
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        self.create_service_admin()
        customer = self.customer_data[0]
        response = self.create_customer(customer)
        self.assertEqual(response.status_code, 201)
        customer_json = response.json()
        customer_uuid = customer_json.get('uuid')
        customer_obj = Customer.objects.filter(uuid=customer_uuid).get()
        self.tenant = Tenant(schema_name=customer_obj.schema_name)
        self.tenant.save()
        self.add_data_to_tenant()

    def create_hourly_instance_usage(self, payer_account_id, bill, ce_pricing,
                                     ce_product, rate, cost, start_hour,
                                     end_hour):
        """Create houlr instance usage."""
        cost_entry = AWSCostEntry(interval_start=start_hour,
                                  interval_end=end_hour,
                                  bill=bill)
        cost_entry.save()
        line_item = AWSCostEntryLineItem(
            invoice_id=self.fake.sha1(raw_output=False),
            line_item_type='Usage',
            usage_account_id=payer_account_id,
            usage_start=start_hour,
            usage_end=end_hour,
            product_code='AmazonEC2',
            usage_type='BoxUsage:c4.xlarge',
            operation='RunInstances',
            availability_zone='us-east-1a',
            resource_id='i-{}'.format(self.fake.ean8()),
            usage_amount=1,
            currency_code='USD',
            unblended_rate=rate,
            unblended_cost=cost,
            blended_rate=rate,
            blended_cost=cost,
            cost_entry=cost_entry,
            cost_entry_bill=bill,
            cost_entry_product=ce_product,
            cost_entry_pricing=ce_pricing)
        line_item.save()

    def add_data_to_tenant(self):
        """Populate tenant with data."""
        payer_account_id = self.fake.ean(length=13)  # pylint: disable=no-member
        self.payer_account_id = payer_account_id
        one_day = datetime.timedelta(days=1)
        one_hour = datetime.timedelta(minutes=60)
        this_hour = timezone.now().replace(microsecond=0, second=0, minute=0)
        yesterday = this_hour - one_day
        bill_start = this_hour.replace(microsecond=0,
                                       second=0,
                                       minute=0,
                                       hour=0,
                                       day=1)
        bill_end = ReportQueryHandler.next_month(bill_start)
        with tenant_context(self.tenant):
            bill = AWSCostEntryBill(bill_type='Anniversary',
                                    payer_account_id=payer_account_id,
                                    billing_period_start=bill_start,
                                    billing_period_end=bill_end)
            bill.save()
            rate = 0.199
            amount = 1
            cost = rate * amount
            # pylint: disable=no-member
            sku = self.fake.pystr(min_chars=12, max_chars=12).upper()
            prod_ec2 = 'Amazon Elastic Compute Cloud'
            ce_product = AWSCostEntryProduct(sku=sku,
                                             product_name=prod_ec2,
                                             product_family='Compute Instance',
                                             service_code='AmazonEC2',
                                             region='US East (N. Virginia)',
                                             instance_type='c4.xlarge',
                                             memory=7.5,
                                             vcpu=4)
            ce_product.save()
            ce_pricing = AWSCostEntryPricing(public_on_demand_cost=rate * 1,
                                             public_on_demand_rate=rate,
                                             term='OnDemand',
                                             unit='Hrs')
            ce_pricing.save()
            current = yesterday
            while current < this_hour:
                end_hour = current + one_hour
                self.create_hourly_instance_usage(payer_account_id, bill,
                                                  ce_pricing, ce_product, rate,
                                                  cost, current, end_hour)
                current = end_hour

    def test_has_filter_no_filter(self):
        """Test the has_filter method with no filter in the query params."""
        handler = ReportQueryHandler({}, '', self.tenant, 'unblended_cost',
                                     'currency_code')
        self.assertFalse(
            handler.check_query_params('filter', 'time_scope_value'))

    def test_has_filter_with_filter(self):
        """Test the has_filter method with filter in the query params."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertIsNotNone(
            handler.check_query_params('filter', 'time_scope_value'))

    def test_get_group_by_no_data(self):
        """Test the get_group_by_data method with no data in the query params."""
        handler = ReportQueryHandler({}, '', self.tenant, 'unblended_cost',
                                     'currency_code')
        self.assertFalse(handler.get_group_by_data('service'))

    def test_get_group_by_with_service_list(self):
        """Test the get_group_by_data method with no data in the query params."""
        expected = ['a', 'b']
        query_string = '?group_by[service]=a&group_by[service]=b'
        handler = ReportQueryHandler({'group_by': {
            'service': expected
        }}, query_string, self.tenant, 'unblended_cost', 'currency_code')
        service = handler.get_group_by_data('service')
        self.assertEqual(expected, service)

    def test_get_resolution_empty_default(self):
        """Test get_resolution returns default when query params are empty."""
        query_params = {}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_resolution(), 'daily')
        self.assertEqual(handler.get_resolution(), 'daily')

    def test_get_resolution_empty_month_time_scope(self):
        """Test get_resolution returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_value': -1}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_resolution(), 'monthly')

    def test_get_resolution_empty_day_time_scope(self):
        """Test get_resolution returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_value': -10}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_resolution(), 'daily')

    def test_get_time_scope_units_empty_default(self):
        """Test get_time_scope_units returns default when query params are empty."""
        query_params = {}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_units(), 'day')
        self.assertEqual(handler.get_time_scope_units(), 'day')

    def test_get_time_scope_units_empty_month_time_scope(self):
        """Test get_time_scope_units returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_value': -1}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_units(), 'month')

    def test_get_time_scope_units_empty_day_time_scope(self):
        """Test get_time_scope_units returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_value': -10}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_units(), 'day')

    def test_get_time_scope_value_empty_default(self):
        """Test get_time_scope_value returns default when query params are empty."""
        query_params = {}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_value(), -10)
        self.assertEqual(handler.get_time_scope_value(), -10)

    def test_get_time_scope_value_empty_month_time_scope(self):
        """Test get_time_scope_value returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_units': 'month'}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_value(), -1)

    def test_get_time_scope_value_empty_day_time_scope(self):
        """Test get_time_scope_value returns default when time_scope is month."""
        query_params = {'filter': {'time_scope_units': 'day'}}
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        self.assertEqual(handler.get_time_scope_value(), -10)

    def test_get_time_frame_filter_current_month(self):
        """Test _get_time_frame_filter for current month."""
        query_params = {
            'filter': {
                'resolution': 'daily',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        next_month = ReportQueryHandler.next_month(current_month)
        start = handler.start_datetime
        end = handler.end_datetime
        interval = handler.time_interval
        self.assertEqual(start, current_month)
        self.assertEqual(end, next_month)
        self.assertIsInstance(interval, list)
        self.assertTrue(len(interval) >= 28)

    def test_get_time_frame_filter_previous_month(self):
        """Test _get_time_frame_filter for previous month."""
        query_params = {
            'filter': {
                'resolution': 'daily',
                'time_scope_value': -2,
                'time_scope_units': 'month'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        prev_month = ReportQueryHandler.previous_month(current_month)
        start = handler.start_datetime
        end = handler.end_datetime
        interval = handler.time_interval
        self.assertEqual(start, prev_month)
        self.assertEqual(end, current_month)
        self.assertIsInstance(interval, list)
        self.assertTrue(len(interval) >= 28)

    def test_get_time_frame_filter_last_ten(self):
        """Test _get_time_frame_filter for last ten days."""
        query_params = {
            'filter': {
                'resolution': 'daily',
                'time_scope_value': -10,
                'time_scope_units': 'day'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        current_day = timezone.now().replace(microsecond=0, second=0, minute=0)
        ten_days_ago = ReportQueryHandler.n_days_ago(current_day, 10)
        start = handler.start_datetime
        end = handler.end_datetime
        interval = handler.time_interval
        self.assertEqual(start, ten_days_ago)
        self.assertEqual(end, current_day)
        self.assertIsInstance(interval, list)
        self.assertTrue(len(interval) == 11)

    def test_get_time_frame_filter_last_thirty(self):
        """Test _get_time_frame_filter for last thirty days."""
        query_params = {
            'filter': {
                'resolution': 'daily',
                'time_scope_value': -30,
                'time_scope_units': 'day'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        current_day = timezone.now().replace(microsecond=0, second=0, minute=0)
        ten_days_ago = ReportQueryHandler.n_days_ago(current_day, 30)
        start = handler.start_datetime
        end = handler.end_datetime
        interval = handler.time_interval
        self.assertEqual(start, ten_days_ago)
        self.assertEqual(end, current_day)
        self.assertIsInstance(interval, list)
        self.assertTrue(len(interval) == 31)

    def test_execute_query_current_month_daily(self):
        """Test execute_query for current month on daily breakdown."""
        query_params = {
            'filter': {
                'resolution': 'daily',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        query_output = handler.execute_query()
        self.assertIsNotNone(query_output.get('data'))
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

    def test_execute_query_current_month_monthly(self):
        """Test execute_query for current month on monthly breakdown."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            }
        }
        handler = ReportQueryHandler(query_params, '', self.tenant,
                                     'unblended_cost', 'currency_code')
        query_output = handler.execute_query()
        self.assertIsNotNone(query_output.get('data'))
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

    def test_execute_query_current_month_by_service(self):
        """Test execute_query for current month on monthly breakdown by service."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            },
            'group_by': {
                'service': ['*']
            }
        }
        handler = ReportQueryHandler(query_params, '?group_by[service]=*',
                                     self.tenant, 'unblended_cost',
                                     'currency_code')
        query_output = handler.execute_query()
        data = query_output.get('data')
        self.assertIsNotNone(data)
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        cmonth_str = current_month.strftime('%Y-%m')
        for data_item in data:
            month_val = data_item.get('date')
            month_data = data_item.get('services')
            self.assertEqual(month_val, cmonth_str)
            self.assertIsInstance(month_data, list)
            for month_item in month_data:
                compute = month_item.get('service')
                self.assertEqual(compute, 'Compute Instance')
                self.assertIsInstance(month_item.get('values'), list)

    def test_execute_query_by_filtered_service(self):
        """Test execute_query monthly breakdown by filtered service."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            },
            'group_by': {
                'service': ['Compute Instance']
            }
        }
        handler = ReportQueryHandler(query_params,
                                     '?group_by[service]=Compute Instance',
                                     self.tenant, 'unblended_cost',
                                     'currency_code')
        query_output = handler.execute_query()
        data = query_output.get('data')
        self.assertIsNotNone(data)
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        cmonth_str = current_month.strftime('%Y-%m')
        for data_item in data:
            month_val = data_item.get('date')
            month_data = data_item.get('services')
            self.assertEqual(month_val, cmonth_str)
            self.assertIsInstance(month_data, list)
            for month_item in month_data:
                compute = month_item.get('service')
                self.assertEqual(compute, 'Compute Instance')
                self.assertIsInstance(month_item.get('values'), list)

    def test_execute_query_current_month_by_account(self):
        """Test execute_query for current month on monthly breakdown by account."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            },
            'group_by': {
                'account': ['*']
            }
        }
        handler = ReportQueryHandler(query_params, '?group_by[account]=*',
                                     self.tenant, 'unblended_cost',
                                     'currency_code')
        query_output = handler.execute_query()
        data = query_output.get('data')
        self.assertIsNotNone(data)
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        cmonth_str = current_month.strftime('%Y-%m')
        for data_item in data:
            month_val = data_item.get('date')
            month_data = data_item.get('accounts')
            self.assertEqual(month_val, cmonth_str)
            self.assertIsInstance(month_data, list)
            for month_item in month_data:
                account = month_item.get('account')
                self.assertEqual(account, self.payer_account_id)
                self.assertIsInstance(month_item.get('values'), list)

    def test_execute_query_by_account_by_service(self):
        """Test execute_query for current month breakdown by account by service."""
        query_params = {
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month'
            },
            'group_by': {
                'account': ['*'],
                'service': ['*']
            }
        }
        query_string = '?group_by[account]=*&group_by[service]=Compute Instance'
        handler = ReportQueryHandler(query_params, query_string, self.tenant,
                                     'unblended_cost', 'currency_code')
        query_output = handler.execute_query()
        data = query_output.get('data')
        self.assertIsNotNone(data)
        self.assertIsNotNone(query_output.get('total'))
        total = query_output.get('total')
        self.assertIsNotNone(total.get('value'))
        self.assertEqual(total.get('value'), Decimal('4.776000000'))

        current_month = timezone.now().replace(microsecond=0,
                                               second=0,
                                               minute=0,
                                               hour=0,
                                               day=1)
        cmonth_str = current_month.strftime('%Y-%m')
        for data_item in data:
            month_val = data_item.get('date')
            month_data = data_item.get('accounts')
            self.assertEqual(month_val, cmonth_str)
            self.assertIsInstance(month_data, list)
            for month_item in month_data:
                account = month_item.get('account')
                self.assertEqual(account, self.payer_account_id)
                self.assertIsInstance(month_item.get('services'), list)
Esempio n. 5
0
class ReportViewTest(IamTestCase):
    """Tests the report view."""
    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        self.create_service_admin()
        customer = self.customer_data[0]
        response = self.create_customer(customer)
        self.assertEqual(response.status_code, 201)
        customer_json = response.json()
        customer_uuid = customer_json.get('uuid')
        customer_obj = Customer.objects.filter(uuid=customer_uuid).get()
        self.tenant = Tenant(schema_name=customer_obj.schema_name)
        self.tenant.save()

    def tearDown(self):
        """Tear down user tests."""
        super().tearDown()
        Customer.objects.all().delete()
        User.objects.all().delete()

    def test_get_costs_anon(self):
        """Test costs reports fail with an anonymous user."""
        url = reverse('reports-costs')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_storage_anon(self):
        """Test inventory storage reports fail with an anonymous user."""
        url = reverse('reports-storage')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_instance_anon(self):
        """Test inventory instance reports fail with an anonymous user."""
        url = reverse('reports-instance-type')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_costs_customer_owner(self):
        """Test costs reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-costs')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_get_instance_customer_owner(self):
        """Test inventory instance reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-instance-type')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_get_storage_customer_owner(self):
        """Test inventory storage reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-storage')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_process_query_parameters(self):
        """Test processing of valid parameters."""
        qs = 'group_by%5Baccount%5D=account1&filter%5Bresolution%5D=daily'
        valid, query_dict = process_query_parameters(qs)
        self.assertTrue(valid)
        self.assertEqual(query_dict.get('group_by'), {'account': ['account1']})
        self.assertEqual(query_dict.get('filter'), {'resolution': 'daily'})

    def test_process_query_parameters_invalid(self):
        """Test processing of invalid parameters."""
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        valid, _ = process_query_parameters(qs)
        self.assertFalse(valid)

    def test_get_costs_invalid_query_param(self):
        """Test costs reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-costs') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_instance_usage_invalid_query_param(self):
        """Test instance usage reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-instance-type') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_storage_usage_invalid_query_param(self):
        """Test storage usage reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-storage') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_tenant_no_group(self):
        """Test get_tenant with a user with no group."""
        user = Mock()
        group = Mock()
        group.id = 909090
        user.groups.first.return_value = group

        with self.assertRaises(ValidationError):
            get_tenant(user)
Esempio n. 6
0
class ReportViewTest(IamTestCase):
    """Tests the report view."""

    def setUp(self):
        """Set up the customer view tests."""
        super().setUp()
        self.create_service_admin()
        customer = self.customer_data[0]
        response = self.create_customer(customer)
        self.assertEqual(response.status_code, 201)
        customer_json = response.json()
        customer_uuid = customer_json.get('uuid')
        customer_obj = Customer.objects.filter(uuid=customer_uuid).get()
        self.tenant = Tenant(schema_name=customer_obj.schema_name)
        self.tenant.save()

        self.report = {
            'group_by': {
                'account': ['*']
            },
            'filter': {
                'resolution': 'monthly',
                'time_scope_value': -1,
                'time_scope_units': 'month',
                'resource_scope': []
            },
            'data': [
                {
                    'date': '2018-07',
                    'accounts': [
                        {
                            'account': '4418636104713',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'account': '4418636104713',
                                    'total': 1826.74238146924
                                }
                            ]
                        },
                        {
                            'account': '8577742690384',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'account': '8577742690384',
                                    'total': 1137.74036198065
                                }
                            ]
                        },
                        {
                            'account': '3474227945050',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'account': '3474227945050',
                                    'total': 1045.80659412797
                                }
                            ]
                        },
                        {
                            'account': '7249815104968',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'account': '7249815104968',
                                    'total': 807.326470618818
                                }
                            ]
                        },
                        {
                            'account': '9420673783214',
                            'values': [
                                {
                                    'date': '2018-07',
                                    'units': 'GB-Mo',
                                    'account': '9420673783214',
                                    'total': 658.306642830709
                                }
                            ]
                        }
                    ]
                }
            ],
            'total': {
                'value': 5475.922451027388,
                'units': 'GB-Mo'
            }
        }

    def tearDown(self):
        """Tear down user tests."""
        super().tearDown()
        Customer.objects.all().delete()
        User.objects.all().delete()

    def test_get_costs_anon(self):
        """Test costs reports fail with an anonymous user."""
        url = reverse('reports-costs')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_storage_anon(self):
        """Test inventory storage reports fail with an anonymous user."""
        url = reverse('reports-storage')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_instance_anon(self):
        """Test inventory instance reports fail with an anonymous user."""
        url = reverse('reports-instance-type')
        client = APIClient()
        response = client.get(url)
        self.assertEqual(response.status_code, 403)

    def test_get_costs_customer_owner(self):
        """Test costs reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-costs')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_get_instance_customer_owner(self):
        """Test inventory instance reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-instance-type')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_get_storage_customer_owner(self):
        """Test inventory storage reports runs with a customer owner."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-storage')
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 200)
        json_result = response.json()
        self.assertIsNotNone(json_result.get('data'))
        self.assertIsInstance(json_result.get('data'), list)
        self.assertTrue(len(json_result.get('data')) > 0)

    def test_process_query_parameters(self):
        """Test processing of valid parameters."""
        qs = 'group_by%5Baccount%5D=account1&filter%5Bresolution%5D=daily'
        valid, query_dict = process_query_parameters(qs)
        self.assertTrue(valid)
        self.assertEqual(query_dict.get('group_by'), {'account': ['account1']})
        self.assertEqual(query_dict.get('filter'), {'resolution': 'daily'})

    def test_process_query_parameters_invalid(self):
        """Test processing of invalid parameters."""
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        valid, _ = process_query_parameters(qs)
        self.assertFalse(valid)

    def test_get_costs_invalid_query_param(self):
        """Test costs reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-costs') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_instance_usage_invalid_query_param(self):
        """Test instance usage reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-instance-type') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_storage_usage_invalid_query_param(self):
        """Test storage usage reports runs with an invalid query param."""
        token = self.get_customer_owner_token(self.customer_data[0])
        qs = 'group_by%5Binvalid%5D=account1&filter%5Bresolution%5D=daily'
        url = reverse('reports-storage') + '?' + qs
        client = APIClient()
        client.credentials(HTTP_AUTHORIZATION=token)
        response = client.get(url)
        self.assertEqual(response.status_code, 400)

    def test_get_tenant_no_group(self):
        """Test get_tenant with a user with no group."""
        user = Mock()
        group = Mock()
        group.id = 909090
        user.groups.first.return_value = group

        with self.assertRaises(ValidationError):
            get_tenant(user)

    def test_get_costs_csv(self):
        """Test CSV output of costs reports."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-costs')
        client = APIClient(HTTP_ACCEPT='text/csv')

        client.credentials(HTTP_AUTHORIZATION=token)

        response = client.get(url)
        response.render()

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.accepted_media_type, 'text/csv')
        self.assertIsInstance(response.accepted_renderer, CSVRenderer)

    def test_get_instance_csv(self):
        """Test CSV output of inventory instance reports."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-instance-type')
        client = APIClient(HTTP_ACCEPT='text/csv')

        client.credentials(HTTP_AUTHORIZATION=token)

        response = client.get(url, content_type='text/csv')
        response.render()

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.accepted_media_type, 'text/csv')
        self.assertIsInstance(response.accepted_renderer, CSVRenderer)

    def test_get_storage_csv(self):
        """Test CSV output of inventory storage reports."""
        token = self.get_customer_owner_token(self.customer_data[0])
        url = reverse('reports-storage')
        client = APIClient(HTTP_ACCEPT='text/csv')

        client.credentials(HTTP_AUTHORIZATION=token)

        response = client.get(url, content_type='text/csv')
        response.render()

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.accepted_media_type, 'text/csv')
        self.assertIsInstance(response.accepted_renderer, CSVRenderer)

    def test_convert_units_success(self):
        """Test unit conversion succeeds."""
        converter = UnitConverter()
        to_unit = 'byte'
        expected_unit = f'{to_unit}-Mo'
        report_total = self.report.get('total', {}).get('value')

        result = _convert_units(converter, self.report, to_unit)
        result_unit = result.get('total', {}).get('units')
        result_total = result.get('total', {}).get('value')

        self.assertEqual(expected_unit, result_unit)
        self.assertEqual(report_total * 1E9, result_total)

    def test_convert_units_list(self):
        """Test that the list check is hit."""
        converter = UnitConverter()
        to_unit = 'byte'
        expected_unit = f'{to_unit}-Mo'
        report_total = self.report.get('total', {}).get('value')

        report = [self.report]
        result = _convert_units(converter, report, to_unit)
        result_unit = result[0].get('total', {}).get('units')
        result_total = result[0].get('total', {}).get('value')

        self.assertEqual(expected_unit, result_unit)
        self.assertEqual(report_total * 1E9, result_total)

    def test_convert_units_total_not_dict(self):
        """Test that the total not dict block is hit."""
        converter = UnitConverter()
        to_unit = 'byte'
        expected_unit = f'{to_unit}-Mo'

        report = self.report['data'][0]['accounts'][0]['values'][0]
        report_total = report.get('total')
        result = _convert_units(converter, report, to_unit)
        result_unit = result.get('units')
        result_total = result.get('total')

        self.assertEqual(expected_unit, result_unit)
        self.assertEqual(report_total * 1E9, result_total)

    @patch('api.report.view.ReportQueryHandler')
    def test_generic_report_with_units_success(self, mock_handler):
        """Test unit conversion succeeds in generic report."""
        mock_handler.return_value.execute_query.return_value = self.report
        params = {
            'group_by[account]': '*',
            'filter[resolution]': 'monthly',
            'filter[time_scope_value]': '-1',
            'filter[time_scope_units]': 'month',
            'units': 'byte'
        }
        user = User.objects.filter(
            username=self.customer_data[0]['owner']['username']
        ).first()

        django_request = HttpRequest()
        qd = QueryDict(mutable=True)
        qd.update(params)
        django_request.GET = qd
        request = Request(django_request)
        request.user = user
        response = _generic_report(
            request,
            'usage_amount',
            'cost_entry_pricing__unit'
        )
        self.assertIsInstance(response, Response)

    @patch('api.report.view.ReportQueryHandler')
    def test_generic_report_with_units_fails_well(self, mock_handler):
        """Test that validation error is thrown for bad unit conversion."""
        mock_handler.return_value.execute_query.return_value = self.report
        # The 'bad' unit here is that the report is in GB-Mo, and can't
        # convert to seconds
        params = {
            'group_by[account]': '*',
            'filter[resolution]': 'monthly',
            'filter[time_scope_value]': '-1',
            'filter[time_scope_units]': 'month',
            'units': 'second'
        }

        user = User.objects.filter(
            username=self.customer_data[0]['owner']['username']
        ).first()

        django_request = HttpRequest()
        qd = QueryDict(mutable=True)
        qd.update(params)
        django_request.GET = qd
        request = Request(django_request)
        request.user = user

        with self.assertRaises(ValidationError):
            _generic_report(request, 'usage_amount', 'cost_entry_pricing__unit')

    def test_find_unit_list(self):
        """Test that the correct unit is returned."""
        expected_unit = 'Hrs'
        data = [
            {'date': '2018-07-22', 'units': '', 'instance_type': 't2.micro', 'total': 30.0, 'count': 0},
            {'date': '2018-07-22', 'units': expected_unit, 'instance_type': 't2.small', 'total': 17.0, 'count': 0},
            {'date': '2018-07-22', 'units': expected_unit, 'instance_type': 't2.micro', 'total': 1.0, 'count': 0}
        ]

        result_unit = _find_unit()(data)
        self.assertEqual(expected_unit, result_unit)

    def test_find_unit_dict(self):
        """Test that the correct unit is returned for a dictionary."""
        data = {'date': '2018-07-22', 'units': '', 'instance_type': 't2.micro', 'total': 30.0, 'count': 0},

        result_unit = _find_unit()(data)
        self.assertIsNone(result_unit)

    def test_fill_in_missing_units_list(self):
        """Test that missing units are filled in."""
        expected_unit = 'Hrs'
        data = [
            {'date': '2018-07-22', 'units': '', 'instance_type': 't2.micro', 'total': 30.0, 'count': 0},
            {'date': '2018-07-22', 'units': expected_unit, 'instance_type': 't2.small', 'total': 17.0, 'count': 0},
            {'date': '2018-07-22', 'units': expected_unit, 'instance_type': 't2.micro', 'total': 1.0, 'count': 0}
        ]

        unit = _find_unit()(data)

        result = _fill_in_missing_units(unit)(data)

        for entry in result:
            self.assertEqual(entry.get('units'), expected_unit)

    def test_fill_in_missing_units_dict(self):
        """Test that missing units are filled in for a dictionary."""
        expected_unit = 'Hrs'
        data = {'date': '2018-07-22', 'units': '', 'instance_type': 't2.micro', 'total': 30.0, 'count': 0}

        result = _fill_in_missing_units(expected_unit)(data)

        self.assertEqual(result.get('units'), expected_unit)