def test_expand_column_infos(self): aggregated_report = ReportConfiguration( domain=self.domain.name, config_id=self.data_source._id, aggregation_columns=["opened_by"], columns=[ { "column_id": self.field_name, "type": "field", "field": self.field_name, "aggregation": "expand", } ], filters=[], ) aggregated_report.save() response = self.client.get( self.single_endpoint(aggregated_report._id)) response_dict = json.loads(response.content) columns = response_dict["columns"] for c in columns: self.assertIn("expand_column_value", c) self.assertSetEqual(set(self.case_property_values), {c['expand_column_value'] for c in columns})
def _create_report(cls): report_config = ReportConfiguration( domain=cls.domain, config_id=cls.data_sources[UCR_SQL_BACKEND]._id, title='foo', filters=[{ "type": "date", "field": "date_as_date", "slug": "date_as_date_filter", "display": "Date as Date filter" }, { "type": "date", "field": "date_as_string", "slug": "date_as_string_filter", "display": "Date as String filter", "compare_as_string": True, }, { "type": "date", "field": "datetime_as_datetime", "slug": "datetime_as_datetime_filter", "display": "Datetime as Datetime filter", "compare_as_string": False, }], aggregation_columns=['doc_id'], columns=[{ # We don't really care what columns are returned, we're testing the filters "type": "field", "display": "doc_id", "field": 'doc_id', 'column_id': 'doc_id', 'aggregation': 'simple' }], ) report_config.save() return report_config
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config_id = self._build_data_source() report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta( created_by_builder=True, builder_report_type=self.report_type ) ) report.validate() report.save() return report
def test_expand_column_infos(self): aggregated_report = ReportConfiguration( domain=self.domain.name, config_id=self.data_source._id, aggregation_columns=["opened_by"], columns=[{ "column_id": self.field_name, "type": "field", "field": self.field_name, "aggregation": "expand", }], filters=[], ) aggregated_report.save() response = self.client.get(self.single_endpoint(aggregated_report._id)) response_dict = json.loads(response.content) columns = response_dict["columns"] for c in columns: self.assertIn("expand_column_value", c) self.assertSetEqual(set(self.case_property_values), {c['expand_column_value'] for c in columns})
def setUpClass(cls): super(TestSimpleReportConfigurationResource, cls).setUpClass() cls.report_columns = [{ "column_id": 'foo', "display": "foo display", "type": "field", "field": "my_field", "aggregation": "simple", }, { "column_id": 'bar', "display": "bar display", "type": "field", "field": "my_field", "aggregation": "simple", }, { "column_id": 'expand', "display": "expand display", "type": "expanded", "field": "my_field", "max_expansion": 10, }] cls.report_filters = [{ 'datatype': 'integer', 'field': 'my_field', 'type': 'dynamic_choice_list', 'slug': 'my_field_filter', }, { 'datatype': 'string', 'field': 'my_other_field', 'type': 'dynamic_choice_list', 'slug': 'my_other_field_filter', }] cls.report_title = "test report" cls.data_source = DataSourceConfiguration( domain=cls.domain.name, referenced_doc_type="XFormInstance", table_id=uuid.uuid4().hex, ) cls.data_source.save() cls.report_configuration = ReportConfiguration( title=cls.report_title, domain=cls.domain.name, config_id=cls.data_source._id, columns=cls.report_columns, filters=cls.report_filters) cls.report_configuration.save() another_report_configuration = ReportConfiguration( domain=cls.domain.name, config_id=cls.data_source._id, columns=[], filters=[]) another_report_configuration.save()
def _create_report(self, aggregation_columns, columns): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source_config._id, title="foo", aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source_config._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _build_report(self, vals, field="my_field", build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: self._new_case({field: v}).save() # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name="foo", referenced_doc_type="CommCareCase", table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": {"type": "property_name", "property_name": "type"}, "property_value": self.case_type, }, configured_indicators=[ { "type": "expression", "expression": {"type": "property_name", "property_name": field}, "column_id": field, "display_name": field, "datatype": "string", } ], ) data_source_config.validate() data_source_config.save() if build_data_source: tasks.rebuild_indicators(data_source_config._id) report_config = ReportConfiguration( domain=self.domain, config_id=data_source_config._id, title="foo", aggregation_columns=["doc_id"], columns=[{"type": "expanded", "field": field, "display": field, "format": "default"}], filters=[], configured_charts=[], ) report_config.save() data_source = ReportFactory.from_spec(report_config) return data_source, data_source.column_configs[0]
def test_unlink_ucr_returns_none_if_not_linked(self): report = ReportConfiguration() report.domain = self.domain report.config_id = '123abd' report.report_meta = ReportMeta() report.save() self.addCleanup(report.delete) unlinked_report = unlink_report(report) self.assertIsNone(unlinked_report)
def _create_report(self, aggregation_columns, columns): backend_id = settings.OVERRIDE_UCR_BACKEND or UCR_SQL_BACKEND report_config = ReportConfiguration( domain=self.domain, config_id=self.data_sources[backend_id]._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns): backend_id = settings.OVERRIDE_UCR_BACKEND or UCR_SQL_BACKEND report_config = ReportConfiguration( domain=self.domain, config_id=self.data_sources[backend_id]._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns, filters=None): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, filters=filters or [], ) report_config.save() return report_config
def _create_report(self, aggregation_columns, columns, sort_expression=None): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) if sort_expression: report_config.sort_expression = sort_expression report_config.save() return report_config
def _create_report(self, aggregation_columns, columns, sort_expression=None): report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, title='foo', aggregation_columns=aggregation_columns, columns=columns, ) if sort_expression: report_config.sort_expression = sort_expression report_config.save() return report_config
def test_updating_report_that_shares_data_source(self): """ If a report builder builder report shares a data source with another report, then editing the report builder report should result in a new data source being created for the report. """ # Make report builder_form = ConfigureListReportForm( self.domain, "Test Report", self.app._id, "form", self.form.unique_id, existing_report=None, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name", "calculation":"Group By"}]', }) self.assertTrue(builder_form.is_valid()) report = builder_form.create_report() # Make another report that references the same data source report_two = ReportConfiguration(domain="domain", config_id=report.config_id) report_two.save() # Make an edit to the first report builder report builder_form = ConfigureListReportForm( self.domain, "Test Report", self.app._id, "form", self.form.unique_id, existing_report=report, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name", "calculation": "Group By"}]', }) self.assertTrue(builder_form.is_valid()) report = builder_form.update_report() self.assertNotEqual(report.config_id, report_two.config_id)
def _create_report(self, master_id=None): data_source = get_sample_data_source() data_source.domain = self.domain data_source.save() self.addCleanup(data_source.delete) report = ReportConfiguration() report.config_id = data_source.get_id report.domain = self.domain report.report_meta = ReportMeta() report.report_meta.master_id = master_id report.save() self.addCleanup(report.delete) return report
def test_updating_report_that_shares_data_source(self): """ If a report builder builder report shares a data source with another report, then editing the report builder report should result in a new data source being created for the report. """ # Make report builder_form = ConfigureListReportForm( "Test Report", self.app._id, "form", self.form.unique_id, existing_report=None, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name"}]', } ) self.assertTrue(builder_form.is_valid()) report = builder_form.create_report() # Make another report that references the same data source report_two = ReportConfiguration( domain="domain", config_id=report.config_id ) report_two.save() # Make an edit to the first report builder report builder_form = ConfigureListReportForm( "Test Report", self.app._id, "form", self.form.unique_id, existing_report=report, data={ 'user_filters': '[]', 'default_filters': '[]', 'columns': '[{"property": "/data/first_name", "display_text": "first name"}]', } ) self.assertTrue(builder_form.is_valid()) report = builder_form.update_report() self.assertNotEqual(report.config_id, report_two.config_id)
def _create_report(domain, title="report", upstream_id=None, should_save=True): data_source = DataSourceConfiguration( domain=domain, table_id=uuid.uuid4().hex, referenced_doc_type='XFormInstance', ) data_source.save() report = ReportConfiguration( domain=domain, config_id=data_source._id, title=title, report_meta=ReportMeta(created_by_builder=True, master_id=upstream_id), ) if should_save: report.save() return report
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config = DataSourceConfiguration( domain=self.domain, display_name=self.ds_builder.data_source_name, referenced_doc_type=self.ds_builder.source_doc_type, # The uuid gets truncated, so it's not really universally unique. table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter=self.ds_builder.filter, configured_indicators=self.ds_builder.indicators, meta=DataSourceMeta(build=DataSourceBuildInformation( source_id=self.report_source_id, app_id=self.app._id, app_version=self.app.version, )) ) data_source_config.validate() data_source_config.save() tasks.rebuild_indicators.delay(data_source_config._id) data_source_config_id = data_source_config._id report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta( created_by_builder=True, builder_report_type=self.report_type ) ) report.validate() report.save() return report
def _build_report(self, vals, field='my_field', build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: update_props = {field: v} if v is not None else {} self._new_case(update_props).save() if build_data_source: tasks.rebuild_indicators(self.data_source_config._id) adapter = get_indicator_adapter(self.data_source_config) adapter.refresh_table() report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[{ "type": "expanded", "field": field, "display": field, "format": "default", }], filters=[], configured_charts=[] ) report_config.save() self.addCleanup(report_config.delete) data_source = ConfigurableReportDataSource.from_spec(report_config) return data_source, data_source.top_level_columns[0]
def _create_report(cls): report_config = ReportConfiguration( domain=cls.domain, config_id=cls.data_sources[UCR_SQL_BACKEND]._id, title='foo', filters=[ { "type": "date", "field": "date_as_date", "slug": "date_as_date_filter", "display": "Date as Date filter" }, { "type": "date", "field": "date_as_string", "slug": "date_as_string_filter", "display": "Date as String filter", "compare_as_string": True, }, { "type": "date", "field": "datetime_as_datetime", "slug": "datetime_as_datetime_filter", "display": "Datetime as Datetime filter", "compare_as_string": False, } ], aggregation_columns=['doc_id'], columns=[{ # We don't really care what columns are returned, we're testing the filters "type": "field", "display": "doc_id", "field": 'doc_id', 'column_id': 'doc_id', 'aggregation': 'simple' }], ) report_config.save() return report_config
def _build_report(self, vals, field='my_field', build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: update_props = {field: v} if v is not None else {} self._new_case(update_props).save() if build_data_source: tasks.rebuild_indicators(self.data_source_config._id) report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[{ "type": "expanded", "field": field, "display": field, "format": "default", }], filters=[], configured_charts=[] ) report_config.save() self.addCleanup(report_config.delete) data_source = ConfigurableReportDataSource.from_spec(report_config) return data_source, data_source.top_level_columns[0]
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source._id reactivated = False if matching_data_source.is_deactivated: matching_data_source.is_deactivated = False reactivated = True changed = False indicators = self.ds_builder.indicators(self._number_columns) if matching_data_source.configured_indicators != indicators: matching_data_source.configured_indicators = indicators changed = True if changed or reactivated: matching_data_source.save() tasks.rebuild_indicators.delay(matching_data_source._id) else: data_source_config_id = self._build_data_source() report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta( created_by_builder=True, builder_report_type=self.report_type ) ) report.validate() report.save() return report
def create_report(self): """ Creates data source and report config. """ matching_data_source = self.ds_builder.get_existing_match() if matching_data_source: data_source_config_id = matching_data_source['id'] else: data_source_config_id = self._build_data_source() report = ReportConfiguration( domain=self.domain, config_id=data_source_config_id, title=self.report_name, aggregation_columns=self._report_aggregation_cols, columns=self._report_columns, filters=self._report_filters, configured_charts=self._report_charts, report_meta=ReportMeta(created_by_builder=True, builder_report_type=self.report_type)) report.validate() report.save() return report
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'string-number', "display_name": 'string-number', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'just_for_sorting' }, "column_id": 'just_for_sorting', "display_name": 'just_for_sorting', "datatype": "string" } ], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[ { "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", "calculate_total": True, }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }, { "type": "field", "field": 'string-number', "display": 'Display Number', "aggregation": "simple", "transform": { "type": "translation", "translations": { "0": "zero", "1": {"en": "one", "es": "uno"}, "2": {"en": "two", "es": "dos"} }, }, } ], filters=[], configured_charts=[], sort_expression=[{'field': 'just_for_sorting', 'order': 'DESC'}] ) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ReportDataTestRow(uuid.uuid4().hex, i, i) for i in range(count)] self._add_rows(rows) return rows def _add_rows(self, rows): pillow = get_case_pillow(ucr_configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, 'just_for_sorting': row.sort_key, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ConfigurableReportDataSource.from_spec(self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) self.assertEqual(10, row['ten']) self.assertEqual(10 * row['number'], row['by_tens']) def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped) def test_total_row(self): rows = self._add_some_rows(3) report_data_source = ConfigurableReportDataSource.from_spec(self.report_config) total_number = sum(row.number for row in rows) self.assertEqual(report_data_source.get_total_row(), ['Total', total_number, '', '', '']) def test_transform(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) rows_by_number = {int(row['number']): row for row in original_data} # Make sure the translations happened self.assertEqual(rows_by_number[0]['string-number'], "zero") self.assertEqual(rows_by_number[1]['string-number'], "one") self.assertEqual(rows_by_number[2]['string-number'], "two") # These last two are untranslated self.assertEqual(rows_by_number[3]['string-number'], "3") self.assertEqual(rows_by_number[4]['string-number'], "4")
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'string-number', "display_name": 'string-number', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'just_for_sorting' }, "column_id": 'just_for_sorting', "display_name": 'just_for_sorting', "datatype": "string" }], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[{ "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", "calculate_total": True, }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }, { "type": "field", "field": 'string-number', "display": 'Display Number', "aggregation": "simple", "transform": { "type": "translation", "translations": { "0": "zero", "1": { "en": "one", "es": "uno" }, "2": { "en": "two", "es": "dos" } }, }, }], filters=[], configured_charts=[], sort_expression=[{ 'field': 'just_for_sorting', 'order': 'DESC' }]) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ ReportDataTestRow(uuid.uuid4().hex, i, i) for i in range(count) ] self._add_rows(rows) return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, 'just_for_sorting': row.sort_key, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) self.assertEqual(10, row['ten']) self.assertEqual(10 * row['number'], row['by_tens']) def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped) def test_total_row(self): rows = self._add_some_rows(3) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) total_number = sum(row.number for row in rows) self.assertEqual(report_data_source.get_total_row(), ['Total', total_number, '', '', '']) def test_transform(self): count = 5 self._add_some_rows(count) report_data_source = ConfigurableReportDataSource.from_spec( self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) rows_by_number = {int(row['number']): row for row in original_data} # Make sure the translations happened self.assertEqual(rows_by_number[0]['string-number'], "zero") self.assertEqual(rows_by_number[1]['string-number'], "one") self.assertEqual(rows_by_number[2]['string-number'], "two") # These last two are untranslated self.assertEqual(rows_by_number[3]['string-number'], "3") self.assertEqual(rows_by_number[4]['string-number'], "4")
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = "test-ucr-report-data" self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type="CommCareCase", table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[ { "type": "expression", "expression": {"type": "property_name", "property_name": "name"}, "column_id": "name", "display_name": "name", "datatype": "string", }, { "type": "expression", "expression": {"type": "property_name", "property_name": "number"}, "column_id": "number", "display_name": "number", "datatype": "integer", }, ], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=["doc_id"], columns=[ {"type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple"}, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": {"type": "constant", "constant": 10}, }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": {"type": "property_name", "property_name": "number"}, "b": {"type": "property_name", "property_name": "ten"}, }, }, }, ], filters=[], configured_charts=[], ) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ReportDataTestRow(uuid.uuid4().hex, i) for i in range(count)] self._add_rows(rows) self.adapter.refresh_table() return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { "_id": uuid.uuid4().hex, "domain": self.domain, "doc_type": "CommCareCase", "type": "city", "name": row.name, "number": row.number, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) @run_with_all_ucr_backends def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ReportFactory.from_spec(self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row["name"] in rows_by_name) self.assertEqual(rows_by_name[row["name"]].number, row["number"]) self.assertEqual(10, row["ten"]) self.assertEqual(10 * row["number"], row["by_tens"]) @run_with_all_ucr_backends def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) @run_with_all_ucr_backends def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped)
def _build_report(self, vals, field='my_field', build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: update_props = {field: v} if v is not None else {} self._new_case(update_props).save() # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": self.case_type, }, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": field }, "column_id": field, "display_name": field, "datatype": "string" }], ) data_source_config.validate() data_source_config.save() self.addCleanup(data_source_config.delete) if build_data_source: tasks.rebuild_indicators(data_source_config._id) adapter = get_indicator_adapter(data_source_config) adapter.refresh_table() report_config = ReportConfiguration(domain=self.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[{ "type": "expanded", "field": field, "display": field, "format": "default", }], filters=[], configured_charts=[]) report_config.save() self.addCleanup(report_config.delete) data_source = ReportFactory.from_spec(report_config) adapter = get_indicator_adapter(data_source_config) if build_data_source: adapter.refresh_table() return data_source, data_source.top_level_columns[0]
def test_report_builder_datasource_deactivation(self): def _get_data_source(id_): return get_datasource_config(id_, self.project.name)[0] # Upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # Create reports and data sources builder_report_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="foo", ) other_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="bar", ) builder_report_data_source.save() other_data_source.save() report_builder_report = ReportConfiguration( domain=self.project.name, config_id=builder_report_data_source._id, report_meta=ReportMeta(created_by_builder=True), ) report_builder_report.save() # downgrade the domain pro_with_rb_sub.cancel_subscription(web_user=self.admin_user.username) # Check that the builder data source is deactivated builder_report_data_source = _get_data_source(builder_report_data_source._id) self.assertTrue(builder_report_data_source.is_deactivated) # Check that the other data source has not been deactivated other_data_source = _get_data_source(other_data_source._id) self.assertFalse(other_data_source.is_deactivated) # upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # check that the data source is activated builder_report_data_source = _get_data_source(builder_report_data_source._id) self.assertFalse(builder_report_data_source.is_deactivated) # delete the data sources builder_report_data_source.delete() other_data_source.delete() # Delete the report report_builder_report.delete() # reset the subscription pro_with_rb_sub.cancel_subscription(web_user=self.admin_user.username)
def _build_report_and_view(cls): # Create Cases cls._new_case({'fruit': 'apple', 'num1': 4, 'num2': 6}).save() # Create report data_source_config = DataSourceConfiguration( domain=cls.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id="woop_woop", configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": cls.case_type, }, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": 'fruit' }, "column_id": 'indicator_col_id_fruit', "display_name": 'indicator_display_name_fruit', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num1' }, "column_id": 'indicator_col_id_num1', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num2' }, "column_id": 'indicator_col_id_num2', "datatype": "integer" }, ], ) data_source_config.validate() data_source_config.save() tasks.rebuild_indicators(data_source_config._id) report_config = ReportConfiguration( domain=cls.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[ { "type": "field", "display": "report_column_display_fruit", "field": 'indicator_col_id_fruit', 'column_id': 'report_column_col_id_fruit', 'aggregation': 'simple' }, { "type": "percent", "display": "report_column_display_percent", 'column_id': 'report_column_col_id_percent', 'format': 'percent', "denominator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num1", "column_id": "report_column_col_id_percent_num1" }, "numerator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num2", "column_id": "report_column_col_id_percent_num2" } }, ], ) report_config.save() view = ConfigurableReport(request=HttpRequest()) view._domain = cls.domain view._lang = "en" view._report_config_id = report_config._id return report_config, view
class ReportDataTest(TestCase): dependent_apps = ['pillowtop'] def setUp(self): # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" } ], ) self.data_source.validate() self.data_source.save() IndicatorSqlAdapter(self.data_source).rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[ { "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", } ], filters=[], configured_charts=[] ) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ReportDataTestRow(uuid.uuid4().hex, i) for i in range(count)] self._add_rows(rows) return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ReportFactory.from_spec(self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped)
def _build_report_and_view(self): # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id="woop_woop", configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": self.case_type, }, configured_indicators=[ { "type": "expression", "expression": { "type": "property_name", "property_name": 'fruit' }, "column_id": 'indicator_col_id_fruit', "display_name": 'indicator_display_name_fruit', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num1' }, "column_id": 'indicator_col_id_num1', "datatype": "integer" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'num2' }, "column_id": 'indicator_col_id_num2', "datatype": "integer" }, ], ) data_source_config.validate() data_source_config.save() self.addCleanup(data_source_config.delete) tasks.rebuild_indicators(data_source_config._id) adapter = get_indicator_adapter(data_source_config) adapter.refresh_table() report_config = ReportConfiguration( domain=self.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[ { "type": "field", "display": "report_column_display_fruit", "field": 'indicator_col_id_fruit', 'column_id': 'report_column_col_id_fruit', 'aggregation': 'simple' }, { "type": "percent", "display": "report_column_display_percent", 'column_id': 'report_column_col_id_percent', 'format': 'percent', "denominator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num1", "column_id": "report_column_col_id_percent_num1" }, "numerator": { "type": "field", "aggregation": "sum", "field": "indicator_col_id_num2", "column_id": "report_column_col_id_percent_num2" } }, ], ) report_config.save() self.addCleanup(report_config.delete) view = ConfigurableReport(request=HttpRequest()) view._domain = self.domain view._lang = "en" view._report_config_id = report_config._id return report_config, view
class ReportDataTest(TestCase): def setUp(self): super(ReportDataTest, self).setUp() # Create report self.domain = 'test-ucr-report-data' self.data_source = DataSourceConfiguration( domain=self.domain, referenced_doc_type='CommCareCase', table_id=uuid.uuid4().hex, configured_filter={}, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": 'name' }, "column_id": 'name', "display_name": 'name', "datatype": "string" }, { "type": "expression", "expression": { "type": "property_name", "property_name": 'number' }, "column_id": 'number', "display_name": 'number', "datatype": "integer" }], ) self.data_source.validate() self.data_source.save() self.adapter = get_indicator_adapter(self.data_source) self.adapter.rebuild_table() self.addCleanup(self.data_source.delete) # initialize a report on the data self.report_config = ReportConfiguration( domain=self.domain, config_id=self.data_source._id, aggregation_columns=['doc_id'], columns=[{ "type": "field", "field": "name", "column_id": "name", "display": "Name", "aggregation": "simple", }, { "type": "field", "field": "number", "column_id": "number", "display": "Number", "aggregation": "simple", }, { "type": "expression", "column_id": "ten", "display": "The Number Ten", "expression": { 'type': 'constant', 'constant': 10, } }, { "type": "expression", "column_id": "by_tens", "display": "Counting by tens", "expression": { "type": "evaluator", "statement": "a * b", "context_variables": { "a": { "type": "property_name", "property_name": "number", }, "b": { "type": "property_name", "property_name": "ten", } } } }], filters=[], configured_charts=[]) self.report_config.save() self.addCleanup(self.report_config.delete) def _add_some_rows(self, count): rows = [ReportDataTestRow(uuid.uuid4().hex, i) for i in range(count)] self._add_rows(rows) self.adapter.refresh_table() return rows def _add_rows(self, rows): pillow = get_kafka_ucr_pillow() pillow.bootstrap(configs=[self.data_source]) def _get_case(row): return { '_id': uuid.uuid4().hex, 'domain': self.domain, 'doc_type': 'CommCareCase', 'type': 'city', 'name': row.name, 'number': row.number, } for row in rows: pillow.process_change(doc_to_change(_get_case(row))) @run_with_all_ucr_backends def test_basic_query(self): # add a few rows to the data source rows = self._add_some_rows(3) # check the returned data from the report looks right report_data_source = ReportFactory.from_spec(self.report_config) report_data = report_data_source.get_data() self.assertEqual(len(rows), len(report_data)) rows_by_name = {r.name: r for r in rows} for row in report_data: self.assertTrue(row['name'] in rows_by_name) self.assertEqual(rows_by_name[row['name']].number, row['number']) self.assertEqual(10, row['ten']) self.assertEqual(10 * row['number'], row['by_tens']) @run_with_all_ucr_backends def test_limit(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) limited_data = report_data_source.get_data(limit=3) self.assertEqual(3, len(limited_data)) self.assertEqual(original_data[:3], limited_data) @run_with_all_ucr_backends def test_skip(self): count = 5 self._add_some_rows(count) report_data_source = ReportFactory.from_spec(self.report_config) original_data = report_data_source.get_data() self.assertEqual(count, len(original_data)) skipped = report_data_source.get_data(start=3) self.assertEqual(count - 3, len(skipped)) self.assertEqual(original_data[3:], skipped)
def test_report_builder_datasource_deactivation(self): def _get_data_source(id_): return get_datasource_config(id_, self.project.name)[0] # Upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) self._subscribe_to_advanced() pro_with_rb_sub = self._subscribe_to_pro_with_rb() # Create reports and data sources builder_report_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="foo", ) other_data_source = DataSourceConfiguration( domain=self.project.name, is_deactivated=False, referenced_doc_type="XFormInstance", table_id="bar", ) builder_report_data_source.save() other_data_source.save() report_builder_report = ReportConfiguration( domain=self.project.name, config_id=builder_report_data_source._id, report_meta=ReportMeta(created_by_builder=True), ) report_builder_report.save() # downgrade the domain community_sub = pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version()) # Check that the builder data source is deactivated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertTrue(builder_report_data_source.is_deactivated) # Check that the other data source has not been deactivated other_data_source = _get_data_source(other_data_source._id) self.assertFalse(other_data_source.is_deactivated) # upgrade the domain # (for the upgrade to work, there has to be an existing subscription, # which is why we subscribe to advanced first) community_sub.change_plan( DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED)) pro_with_rb_sub = self._subscribe_to_pro_with_rb() # check that the data source is activated builder_report_data_source = _get_data_source( builder_report_data_source._id) self.assertFalse(builder_report_data_source.is_deactivated) # delete the data sources builder_report_data_source.delete() other_data_source.delete() # Delete the report report_builder_report.delete() # reset the subscription pro_with_rb_sub.change_plan( DefaultProductPlan.get_default_plan_version())
def _build_report(self, vals, field='my_field', build_data_source=True): """ Build a new report, and populate it with cases. Return a ConfigurableReportDataSource and a FieldColumn :param vals: List of values to populate the given report field with. :param field: The name of a field in the data source/report :return: Tuple containing a ConfigurableReportDataSource and FieldColumn. The column is a column mapped to the given field. """ # Create Cases for v in vals: update_props = {field: v} if v is not None else {} self._new_case(update_props).save() # Create report data_source_config = DataSourceConfiguration( domain=self.domain, display_name='foo', referenced_doc_type='CommCareCase', table_id=_clean_table_name(self.domain, str(uuid.uuid4().hex)), configured_filter={ "type": "boolean_expression", "operator": "eq", "expression": { "type": "property_name", "property_name": "type" }, "property_value": self.case_type, }, configured_indicators=[{ "type": "expression", "expression": { "type": "property_name", "property_name": field }, "column_id": field, "display_name": field, "datatype": "string" }], ) data_source_config.validate() data_source_config.save() self.addCleanup(data_source_config.delete) if build_data_source: tasks.rebuild_indicators(data_source_config._id) adapter = get_indicator_adapter(data_source_config) adapter.refresh_table() report_config = ReportConfiguration( domain=self.domain, config_id=data_source_config._id, title='foo', aggregation_columns=['doc_id'], columns=[{ "type": "expanded", "field": field, "display": field, "format": "default", }], filters=[], configured_charts=[] ) report_config.save() self.addCleanup(report_config.delete) data_source = ReportFactory.from_spec(report_config) adapter = get_indicator_adapter(data_source_config) if build_data_source: adapter.refresh_table() return data_source, data_source.top_level_columns[0]
def setUpClass(cls): super(TestSimpleReportConfigurationResource, cls).setUpClass() cls.report_columns = [ { "column_id": 'foo', "display": "foo display", "type": "field", "field": "my_field", "aggregation": "simple", }, { "column_id": 'bar', "display": "bar display", "type": "field", "field": "my_field", "aggregation": "simple", }, { "column_id": 'expand', "display": "expand display", "type": "expanded", "field": "my_field", "max_expansion": 10, } ] cls.report_filters = [ { 'datatype': 'integer', 'field': 'my_field', 'type': 'dynamic_choice_list', 'slug': 'my_field_filter', }, { 'datatype': 'string', 'field': 'my_other_field', 'type': 'dynamic_choice_list', 'slug': 'my_other_field_filter', } ] cls.report_title = "test report" cls.data_source = DataSourceConfiguration( domain=cls.domain.name, referenced_doc_type="XFormInstance", table_id=uuid.uuid4().hex, ) cls.data_source.save() cls.report_configuration = ReportConfiguration( title=cls.report_title, domain=cls.domain.name, config_id=cls.data_source._id, columns=cls.report_columns, filters=cls.report_filters ) cls.report_configuration.save() another_report_configuration = ReportConfiguration( domain=cls.domain.name, config_id=cls.data_source._id, columns=[], filters=[] ) another_report_configuration.save()