class ReportManifestDBAccessorTest(IamTestCase):
    """Test cases for the ReportManifestDBAccessor."""
    def setUp(self):
        """Set up the test class."""
        super().setUp()
        self.schema = self.schema_name
        billing_start = DateAccessor().today_with_timezone('UTC').replace(
            day=1)
        self.manifest_dict = {
            'assembly_id': '1234',
            'billing_period_start_datetime': billing_start,
            'num_total_files': 2,
            'provider_uuid': self.provider_uuid,
        }
        self.manifest_accessor = ReportManifestDBAccessor()

    def tearDown(self):
        """Tear down the test class."""
        super().tearDown()
        with schema_context(self.schema):
            manifests = self.manifest_accessor._get_db_obj_query().all()
            for manifest in manifests:
                self.manifest_accessor.delete(manifest)

    def test_initializer(self):
        """Test the initializer."""
        accessor = ReportManifestDBAccessor()
        self.assertIsNotNone(accessor._table)

    def test_get_manifest(self):
        """Test that the right manifest is returned."""
        with schema_context(self.schema):
            added_manifest = self.manifest_accessor.add(**self.manifest_dict)

            assembly_id = self.manifest_dict.get('assembly_id')
            provider_uuid = self.manifest_dict.get('provider_uuid')
            manifest = self.manifest_accessor.get_manifest(
                assembly_id, provider_uuid)

        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)
        self.assertEqual(manifest.assembly_id, assembly_id)
        self.assertEqual(manifest.provider_id, provider_uuid)
        self.assertEqual(manifest.num_total_files,
                         self.manifest_dict.get('num_total_files'))

    def test_get_manifest_by_id(self):
        """Test that the right manifest is returned by id."""
        with schema_context(self.schema):
            added_manifest = self.manifest_accessor.add(**self.manifest_dict)
            manifest = self.manifest_accessor.get_manifest_by_id(
                added_manifest.id)
        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)

    def test_mark_manifest_as_updated(self):
        """Test that the manifest is marked updated."""
        with schema_context(self.schema):
            manifest = self.manifest_accessor.add(**self.manifest_dict)
            now = DateAccessor().today_with_timezone('UTC')
            self.manifest_accessor.mark_manifest_as_updated(manifest)
            self.assertGreater(manifest.manifest_updated_datetime, now)

    def test_mark_manifest_as_completed(self):
        """Test that the manifest is marked updated."""
        manifest = self.manifest_accessor.add(**self.manifest_dict)
        now = DateAccessor().today_with_timezone('UTC')
        self.manifest_accessor.mark_manifest_as_completed(manifest)
        self.assertGreater(manifest.manifest_completed_datetime, now)

    def test_get_manifest_list_for_provider_and_bill_date(self):
        """Test that all manifests are returned for a provider and bill."""
        bill_date = self.manifest_dict['billing_period_start_datetime'].date()
        manifest_dict = copy.deepcopy(self.manifest_dict)
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 1)

        manifest_dict['assembly_id'] = '2345'
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 2)

        manifest_dict['assembly_id'] = '3456'
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 3)

    def test_get_last_report_completed_datetime(self):
        """Test that the last completed report datetime is returned."""
        manifest = self.manifest_accessor.add(**self.manifest_dict)
        earlier_time = DateAccessor().today_with_timezone('UTC')
        later_time = earlier_time + datetime.timedelta(hours=1)

        ReportStatsDBAccessor(
            'earlier_report',
            manifest.id).update(last_completed_datetime=earlier_time)
        ReportStatsDBAccessor(
            'later_report',
            manifest.id).update(last_completed_datetime=later_time)

        result = self.manifest_accessor.get_last_report_completed_datetime(
            manifest.id)

        self.assertEqual(result, later_time)
class ReportManifestDBAccessorTest(IamTestCase):
    """Test cases for the ReportManifestDBAccessor."""
    def setUp(self):
        """Set up the test class."""
        super().setUp()
        self.schema = self.schema_name
        self.billing_start = DateAccessor().today_with_timezone("UTC").replace(
            day=1)
        self.manifest_dict = {
            "assembly_id": "1234",
            "billing_period_start_datetime": self.billing_start,
            "num_total_files": 2,
            "provider_uuid": self.provider_uuid,
        }
        self.manifest_accessor = ReportManifestDBAccessor()

    def tearDown(self):
        """Tear down the test class."""
        super().tearDown()
        with schema_context(self.schema):
            manifests = self.manifest_accessor._get_db_obj_query().all()
            for manifest in manifests:
                self.manifest_accessor.delete(manifest)

    def test_initializer(self):
        """Test the initializer."""
        accessor = ReportManifestDBAccessor()
        self.assertIsNotNone(accessor._table)

    def test_get_manifest(self):
        """Test that the right manifest is returned."""
        with schema_context(self.schema):
            added_manifest = self.manifest_accessor.add(**self.manifest_dict)

            assembly_id = self.manifest_dict.get("assembly_id")
            provider_uuid = self.manifest_dict.get("provider_uuid")
            manifest = self.manifest_accessor.get_manifest(
                assembly_id, provider_uuid)

        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)
        self.assertEqual(manifest.assembly_id, assembly_id)
        self.assertEqual(manifest.provider_id, provider_uuid)
        self.assertEqual(manifest.num_total_files,
                         self.manifest_dict.get("num_total_files"))

    def test_get_manifest_by_id(self):
        """Test that the right manifest is returned by id."""
        with schema_context(self.schema):
            added_manifest = self.manifest_accessor.add(**self.manifest_dict)
            manifest = self.manifest_accessor.get_manifest_by_id(
                added_manifest.id)
        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)

    def test_mark_manifest_as_updated(self):
        """Test that the manifest is marked updated."""
        with schema_context(self.schema):
            manifest = self.manifest_accessor.add(**self.manifest_dict)
            now = DateAccessor().today_with_timezone("UTC")
            self.manifest_accessor.mark_manifest_as_updated(manifest)
            self.assertGreater(manifest.manifest_updated_datetime, now)

    def test_mark_manifest_as_updated_none_manifest(self):
        """Test that a none manifest doesn't update failure."""
        try:
            self.manifest_accessor.mark_manifest_as_updated(None)
        except Exception as err:
            self.fail(f"Test failed with error: {err}")

    def test_mark_manifest_as_completed_none_manifest(self):
        """Test that a none manifest doesn't complete failure."""
        try:
            self.manifest_accessor.mark_manifest_as_completed(None)
        except Exception as err:
            self.fail(f"Test failed with error: {err}")

    def test_get_manifest_list_for_provider_and_bill_date(self):
        """Test that all manifests are returned for a provider and bill."""
        bill_date = self.manifest_dict["billing_period_start_datetime"].date()
        manifest_dict = copy.deepcopy(self.manifest_dict)
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 1)

        manifest_dict["assembly_id"] = "2345"
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 2)

        manifest_dict["assembly_id"] = "3456"
        self.manifest_accessor.add(**manifest_dict)
        result = self.manifest_accessor.get_manifest_list_for_provider_and_bill_date(
            self.provider_uuid, bill_date)
        self.assertEqual(len(result), 3)

    def test_get_last_seen_manifest_ids(self):
        """Test that get_last_seen_manifest_ids returns the appropriate assembly_ids."""
        # test that the most recently seen manifests that haven't been processed are returned
        manifest_dict2 = {
            "assembly_id": "5678",
            "billing_period_start_datetime": self.billing_start,
            "num_total_files": 1,
            "provider_uuid": "00000000-0000-0000-0000-000000000002",
        }
        manifest = self.manifest_accessor.add(**self.manifest_dict)
        manifest2 = self.manifest_accessor.add(**manifest_dict2)
        assembly_ids = self.manifest_accessor.get_last_seen_manifest_ids(
            self.billing_start)
        self.assertEqual(assembly_ids,
                         [manifest.assembly_id, manifest2.assembly_id])

        # test that when the manifest's files have been processed - it is no longer returned
        manifest2_helper = ManifestCreationHelper(
            manifest2.id, manifest_dict2.get("num_total_files"),
            manifest_dict2.get("assembly_id"))

        manifest2_helper.generate_test_report_files()
        manifest2_helper.process_all_files()

        assembly_ids = self.manifest_accessor.get_last_seen_manifest_ids(
            self.billing_start)
        self.assertEqual(assembly_ids, [manifest.assembly_id])

        # test that of two manifests with the same provider_ids - that only the most recently
        # seen is returned
        manifest_dict3 = {
            "assembly_id": "91011",
            "billing_period_start_datetime": self.billing_start,
            "num_total_files": 1,
            "provider_uuid": self.provider_uuid,
        }
        manifest3 = self.manifest_accessor.add(**manifest_dict3)
        assembly_ids = self.manifest_accessor.get_last_seen_manifest_ids(
            self.billing_start)
        self.assertEqual(assembly_ids, [manifest3.assembly_id])

        # test that manifests for a different billing month are not returned
        current_month = self.billing_start
        calculated_month = current_month + relativedelta(months=-2)
        manifest3.billing_period_start_datetime = calculated_month
        manifest3.save()
        assembly_ids = self.manifest_accessor.get_last_seen_manifest_ids(
            self.billing_start)
        self.assertEqual(assembly_ids, [manifest.assembly_id])

    def test_is_last_completed_datetime_null(self):
        """Test is last completed datetime is null."""
        manifest_id = 123456789
        self.assertTrue(
            ReportManifestDBAccessor().is_last_completed_datetime_null(
                manifest_id))
        baker.make(CostUsageReportManifest, id=manifest_id)
        baker.make(CostUsageReportStatus,
                   manifest_id=manifest_id,
                   last_completed_datetime=None)
        self.assertTrue(
            ReportManifestDBAccessor().is_last_completed_datetime_null(
                manifest_id))

        CostUsageReportStatus.objects.filter(manifest_id=manifest_id).update(
            last_completed_datetime=FAKE.date())

        self.assertFalse(
            ReportManifestDBAccessor().is_last_completed_datetime_null(
                manifest_id))
Example #3
0
class OCPCloudReportSummaryUpdaterTest(MasuTestCase):
    """Test cases for the OCPCloudReportSummaryUpdaterTest class."""
    @classmethod
    def setUpClass(cls):
        """Set up the test class with required objects."""
        super().setUpClass()
        cls.date_accessor = DateAccessor()

    def setUp(self):
        """Setup tests."""
        super().setUp()
        self.column_map = ReportingCommonDBAccessor().column_map
        self.accessor = AWSReportDBAccessor(schema='acct10001',
                                            column_map=self.column_map)
        self.manifest_accessor = ReportManifestDBAccessor()

    def tearDown(self):
        """Return the database to a pre-test state."""
        self.accessor._session.rollback()

        aws_tables = list(AWS_CUR_TABLE_MAP.values())
        with AWSReportDBAccessor(self.test_schema,
                                 self.column_map) as aws_accessor:
            aws_accessor._session.rollback()
            for table_name in aws_tables:
                tables = aws_accessor._get_db_obj_query(table_name).all()
                for table in tables:
                    aws_accessor._session.delete(table)
                aws_accessor.commit()

        ocp_tables = list(OCP_REPORT_TABLE_MAP.values())
        with OCPReportDBAccessor(self.test_schema,
                                 self.column_map) as ocp_accessor:
            for table_name in ocp_tables:
                tables = ocp_accessor._get_db_obj_query(table_name).all()
                for table in tables:
                    ocp_accessor._session.delete(table)
                ocp_accessor.commit()

        manifests = self.manifest_accessor._get_db_obj_query().all()
        for manifest in manifests:
            self.manifest_accessor.delete(manifest)
        self.manifest_accessor.commit()

    def _generate_ocp_on_aws_data(self):
        """Test that the OCP on AWS cost summary table is populated."""
        creator = ReportObjectCreator(self.accessor, self.column_map,
                                      self.accessor.report_schema.column_types)

        bill_ids = []

        today = DateAccessor().today_with_timezone('UTC')
        last_month = today - relativedelta.relativedelta(months=1)
        resource_id = 'i-12345'
        for cost_entry_date in (today, last_month):
            bill = creator.create_cost_entry_bill(cost_entry_date)
            bill_ids.append(str(bill.id))
            cost_entry = creator.create_cost_entry(bill, cost_entry_date)
            product = creator.create_cost_entry_product('Compute Instance')
            pricing = creator.create_cost_entry_pricing()
            reservation = creator.create_cost_entry_reservation()
            creator.create_cost_entry_line_item(bill,
                                                cost_entry,
                                                product,
                                                pricing,
                                                reservation,
                                                resource_id=resource_id)

        self.accessor.populate_line_item_daily_table(last_month, today,
                                                     bill_ids)

        with OCPReportDBAccessor(self.test_schema,
                                 self.column_map) as ocp_accessor:
            cluster_id = self.ocp_provider_resource_name
            with ProviderDBAccessor(provider_uuid=self.ocp_test_provider_uuid
                                    ) as provider_access:
                provider_id = provider_access.get_provider().id

            for cost_entry_date in (today, last_month):
                period = creator.create_ocp_report_period(
                    cost_entry_date,
                    provider_id=provider_id,
                    cluster_id=cluster_id)
                report = creator.create_ocp_report(period, cost_entry_date)
                creator.create_ocp_usage_line_item(period,
                                                   report,
                                                   resource_id=resource_id)
            cluster_id = get_cluster_id_from_provider(
                self.ocp_test_provider_uuid)
            ocp_accessor.populate_line_item_daily_table(
                last_month, today, cluster_id)

    def test_get_infra_db_key_for_provider_type(self):
        """Test db_key private method for OCP-on-AWS infrastructure map."""
        with ProviderDBAccessor(
                self.ocp_test_provider_uuid) as provider_accessor:
            provider = provider_accessor.get_provider()
        updater = OCPCloudReportSummaryUpdater(schema='acct10001',
                                               provider=provider,
                                               manifest=None)
        self.assertEqual(updater._get_infra_db_key_for_provider_type('AWS'),
                         'aws_uuid')
        self.assertEqual(
            updater._get_infra_db_key_for_provider_type('AWS-local'),
            'aws_uuid')
        self.assertEqual(updater._get_infra_db_key_for_provider_type('OCP'),
                         'ocp_uuid')
        self.assertEqual(updater._get_infra_db_key_for_provider_type('WRONG'),
                         None)

    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.AWSReportDBAccessor.populate_ocp_on_aws_cost_daily_summary'
    )
    @patch(
        'masu.database.ocp_report_db_accessor.OCPReportDBAccessor.populate_cost_summary_table'
    )
    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.OCPCloudReportSummaryUpdater._get_ocp_cluster_id_for_provider'
    )
    def test_update_summary_tables_with_ocp_provider(self, mock_utility,
                                                     mock_ocp,
                                                     mock_ocp_on_aws):
        """Test that summary tables are properly run for an OCP provider."""
        fake_cluster = 'my-ocp-cluster'
        mock_utility.return_value = fake_cluster
        start_date = self.date_accessor.today_with_timezone('UTC')
        end_date = start_date + datetime.timedelta(days=1)
        start_date_str = start_date.strftime('%Y-%m-%d')
        end_date_str = end_date.strftime('%Y-%m-%d')
        with ProviderDBAccessor(
                self.ocp_test_provider_uuid) as provider_accessor:
            provider = provider_accessor.get_provider()
        updater = OCPCloudReportSummaryUpdater(schema='acct10001',
                                               provider=provider,
                                               manifest=None)
        updater.update_summary_tables(start_date_str, end_date_str)

        mock_ocp_on_aws.assert_called_with(start_date_str, end_date_str,
                                           fake_cluster, [])
        mock_ocp.assert_called_with(fake_cluster, start_date_str, end_date_str)

    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.AWSReportDBAccessor.populate_ocp_on_aws_cost_daily_summary'
    )
    @patch(
        'masu.database.ocp_report_db_accessor.OCPReportDBAccessor.populate_cost_summary_table'
    )
    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.get_bills_from_provider')
    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.OCPCloudReportSummaryUpdater._get_ocp_cluster_id_for_provider'
    )
    def test_update_summary_tables_with_aws_provider(self,
                                                     mock_cluster_id_utility,
                                                     mock_utility, mock_ocp,
                                                     mock_ocp_on_aws):
        """Test that summary tables are properly run for an OCP provider."""
        fake_cluster_id = 'my-ocp-cluster'
        mock_cluster_id_utility.return_value = fake_cluster_id

        fake_bills = [Mock(), Mock()]
        fake_bills[0].id = 1
        fake_bills[1].id = 2
        bill_ids = [str(bill.id) for bill in fake_bills]
        mock_utility.return_value = fake_bills
        start_date = self.date_accessor.today_with_timezone('UTC')
        end_date = start_date + datetime.timedelta(days=1)
        start_date_str = start_date.strftime('%Y-%m-%d')
        end_date_str = end_date.strftime('%Y-%m-%d')
        with ProviderDBAccessor(
                self.aws_test_provider_uuid) as provider_accessor:
            provider = provider_accessor.get_provider()
        updater = OCPCloudReportSummaryUpdater(schema='acct10001',
                                               provider=provider,
                                               manifest=None)
        updater.update_summary_tables(start_date_str, end_date_str)
        mock_ocp_on_aws.assert_called_with(start_date_str, end_date_str,
                                           fake_cluster_id, bill_ids)
        mock_ocp.assert_called_with(fake_cluster_id, start_date_str,
                                    end_date_str)

    @patch(
        'masu.processor.ocp.ocp_cloud_summary_updater.AWSReportDBAccessor.populate_ocp_on_aws_cost_daily_summary'
    )
    @patch(
        'masu.database.ocp_report_db_accessor.OCPReportDBAccessor.populate_cost_summary_table'
    )
    def test_update_summary_tables_no_ocp_on_aws(self, mock_ocp,
                                                 mock_ocp_on_aws):
        """Test that summary tables do not run when OCP-on-AWS does not exist."""
        test_provider_list = [
            self.aws_test_provider_uuid, self.ocp_test_provider_uuid
        ]

        for provider_uuid in test_provider_list:
            start_date = self.date_accessor.today_with_timezone('UTC')
            end_date = start_date + datetime.timedelta(days=1)
            start_date_str = start_date.strftime('%Y-%m-%d')
            end_date_str = end_date.strftime('%Y-%m-%d')

            with ProviderDBAccessor(provider_uuid) as provider_accessor:
                provider = provider_accessor.get_provider()

            updater = OCPCloudReportSummaryUpdater(schema='acct10001',
                                                   provider=provider,
                                                   manifest=None)

            updater.update_summary_tables(start_date_str, end_date_str)
            mock_ocp.assert_called()
            mock_ocp_on_aws.assert_not_called()

    def test_update_summary_tables(self):
        """Test that summary tables are updated correctly."""
        self._generate_ocp_on_aws_data()

        start_date = self.date_accessor.today_with_timezone('UTC')
        end_date = start_date + datetime.timedelta(days=1)
        start_date_str = start_date.strftime('%Y-%m-%d')
        end_date_str = end_date.strftime('%Y-%m-%d')
        with ProviderDBAccessor(
                self.ocp_test_provider_uuid) as provider_accessor:
            provider = provider_accessor.get_provider()
        updater = OCPCloudReportSummaryUpdater(schema='acct10001',
                                               provider=provider,
                                               manifest=None)

        with AWSReportDBAccessor(self.test_schema,
                                 self.column_map) as aws_accessor:
            summary_table_name = AWS_CUR_TABLE_MAP['ocp_on_aws_daily_summary']
            query = aws_accessor._get_db_obj_query(summary_table_name)
            initial_count = query.count()
            updater.update_summary_tables(start_date_str, end_date_str)
            self.assertNotEqual(query.count(), initial_count)
Example #4
0
class ReportManifestDBAccessorTest(IamTestCase):
    """Test cases for the ReportManifestDBAccessor."""
    def setUp(self):
        """Set up the test class."""
        super().setUp()
        self.schema = self.schema_name

        billing_start = DateAccessor().today_with_timezone('UTC').replace(
            day=1)
        self.manifest_dict = {
            'assembly_id': '1234',
            'billing_period_start_datetime': billing_start,
            'num_total_files': 2,
            'provider_id': 1,
        }
        self.manifest_accessor = ReportManifestDBAccessor()

    def tearDown(self):
        """Tear down the test class."""
        super().tearDown()
        with schema_context(self.schema):
            manifests = self.manifest_accessor._get_db_obj_query().all()
            for manifest in manifests:
                self.manifest_accessor.delete(manifest)

    def test_initializer(self):
        """Test the initializer."""
        accessor = ReportManifestDBAccessor()
        self.assertIsNotNone(accessor._table)

    def test_get_manifest(self):
        """Test that the right manifest is returned."""
        with schema_context(self.schema):
            added_manifest = self.manifest_accessor.add(**self.manifest_dict)

            assembly_id = self.manifest_dict.get('assembly_id')
            provider_id = self.manifest_dict.get('provider_id')
            manifest = self.manifest_accessor.get_manifest(
                assembly_id, provider_id)

        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)
        self.assertEqual(manifest.assembly_id, assembly_id)
        self.assertEqual(manifest.provider_id, provider_id)
        self.assertEqual(manifest.num_total_files,
                         self.manifest_dict.get('num_total_files'))

    def test_get_manifest_by_id(self):
        """Test that the right manifest is returned by id."""
        with schema_context(self.schema):

            added_manifest = self.manifest_accessor.add(**self.manifest_dict)
            manifest = self.manifest_accessor.get_manifest_by_id(
                added_manifest.id)
        self.assertIsNotNone(manifest)
        self.assertEqual(added_manifest, manifest)

    def test_mark_manifest_as_updated(self):
        """Test that the manifest is marked updated."""
        with schema_context(self.schema):
            manifest = self.manifest_accessor.add(**self.manifest_dict)
            now = DateAccessor().today_with_timezone('UTC')
            self.manifest_accessor.mark_manifest_as_updated(manifest)
            self.assertGreater(manifest.manifest_updated_datetime, now)
class ReportStatsDBAccessorTest(MasuTestCase):
    """Test Cases for the ReportStatsDBAccessor object."""
    def setUp(self):
        """Set up the test class."""
        super().setUp()
        billing_start = datetime.utcnow().replace(day=1)
        manifest_dict = {
            'assembly_id': '1234',
            'billing_period_start_datetime': billing_start,
            'num_total_files': 2,
            'provider_uuid': self.aws_provider_uuid,
        }
        self.manifest_accessor = ReportManifestDBAccessor()

        manifest = self.manifest_accessor.add(**manifest_dict)
        self.manifest_accessor.commit()
        self.manifest_id = manifest.id

    def tearDown(self):
        """Tear down the test class."""
        manifests = self.manifest_accessor._get_db_obj_query().all()
        for manifest in manifests:
            self.manifest_accessor.delete(manifest)
        self.manifest_accessor.commit()
        self.manifest_accessor.close_session()

    def test_initializer(self):
        """Test Initializer"""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        self.assertIsNotNone(saver._obj)

    def test_initializer_preexisting_report(self):
        """Test getting a new accessor stats on a preexisting report."""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        saver.update(
            cursor_position=33,
            last_completed_datetime='2011-1-1 11:11:11',
            last_started_datetime='2022-2-2 22:22:22',
            etag='myetag',
        )
        saver.commit()

        self.assertIsNotNone(saver._obj)

        # Get another accessor for the same report and verify we get back the right information.
        saver2 = ReportStatsDBAccessor('myreport', self.manifest_id)
        last_completed = saver2.get_last_completed_datetime()

        self.assertEqual(last_completed.year, 2011)
        self.assertEqual(last_completed.month, 1)
        self.assertEqual(last_completed.day, 1)
        self.assertEqual(last_completed.hour, 11)
        self.assertEqual(last_completed.minute, 11)
        self.assertEqual(last_completed.second, 11)

        self.assertEqual(saver.get_etag(), 'myetag')

    def test_add_remove(self):
        """Test basic add/remove logic."""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        saver.commit()

        self.assertTrue(saver.does_db_entry_exist())
        returned_obj = saver._get_db_obj_query()
        self.assertEqual(returned_obj.first().report_name, 'myreport')

        saver.delete()
        saver.commit()
        returned_obj = saver._get_db_obj_query()
        self.assertIsNone(returned_obj.first())
        saver.close_session()

    def test_update(self):
        """Test updating an existing row."""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        saver.commit()

        returned_obj = saver._get_db_obj_query()
        self.assertEqual(returned_obj.first().report_name, 'myreport')

        saver.update(
            cursor_position=33,
            last_completed_datetime=parser.parse('2011-1-1 11:11:11'),
            last_started_datetime=parser.parse('2022-2-2 22:22:22'),
            etag='myetag',
        )
        saver.commit()

        last_completed = saver.get_last_completed_datetime()
        self.assertEqual(last_completed.year, 2011)
        self.assertEqual(last_completed.month, 1)
        self.assertEqual(last_completed.day, 1)
        self.assertEqual(last_completed.hour, 11)
        self.assertEqual(last_completed.minute, 11)
        self.assertEqual(last_completed.second, 11)

        last_started = saver.get_last_started_datetime()
        self.assertEqual(last_started.year, 2022)
        self.assertEqual(last_started.month, 2)
        self.assertEqual(last_started.day, 2)
        self.assertEqual(last_started.hour, 22)
        self.assertEqual(last_started.minute, 22)
        self.assertEqual(last_started.second, 22)

        self.assertEqual(saver.get_etag(), 'myetag')

        saver.delete()
        saver.commit()
        returned_obj = saver._get_db_obj_query()
        self.assertIsNone(returned_obj.first())
        saver.close_session()

    def test_log_last_started_datetime(self):
        """Test convience function for last started processing time."""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        saver.log_last_started_datetime()
        saver.commit()

        # FIXME: missing asserts
        saver.delete()
        saver.commit()
        saver.close_session()

    def test_log_last_completed_datetime(self):
        """Test convience function for last completed processing time."""
        saver = ReportStatsDBAccessor('myreport', self.manifest_id)
        saver.log_last_completed_datetime()
        saver.commit()

        # FIXME: missing asserts
        saver.delete()
        saver.commit()
        saver.close_session()